diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 845ca06..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.pc diff --git a/COPYING b/COPYING deleted file mode 100644 index 754bfe4..0000000 --- a/COPYING +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2009-2015 Various Contributors (see individual files and source control) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..bc136d0 --- /dev/null +++ b/README @@ -0,0 +1,5 @@ +Repository discontinued +----------------------- + +The repository is for historical purposes only, it was obsoleted and +no longer available starting with mr14.0. diff --git a/README.md b/README.md deleted file mode 100644 index 631e620..0000000 --- a/README.md +++ /dev/null @@ -1,128 +0,0 @@ -examples of messages for testing funtionality ---------------------------------------------- - -* mod_sipwise_lastactivity: -``` - - - -``` - -``` - - - -``` - -* mod_sipwise_vcard_cusax: -``` - - - -``` -response: -``` - - - 43991002@192.168.1.102 - - 43991002 - default-customer@default.invalid - - -``` - -* mod_sipwise_vhosts_sql: -``` - - - -``` -response: -``` - - - - - - -``` - -* mod_sipwise_vjud: - -discover search fields -``` - - - -``` -response: -``` - - - Use the enclosed form to search - - User Directory Search - Please provide the following information to search for subscribers - jabber:iq:search - - - - - - -``` - -search domain: -``` - - - - jabber:iq:search - - - 192.168.1.102 - - - - -``` -response: -``` - - - - jabber:iq:search - - 192.168.1.102 - - - -``` - -search number: -``` - - - - jabber:iq:search - - - 43991003 - - - - -``` -response: -``` - - - - jabber:iq:search - - 43991003@192.168.1.102 - - - -``` diff --git a/debian/.gitignore b/debian/.gitignore deleted file mode 100644 index 0954f39..0000000 --- a/debian/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.debhelper -*.log -*.substvars -/.debhelper/ -/debhelper-build-stamp -/files -/ngcp-prosody-modules/ diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 9866288..0000000 --- a/debian/changelog +++ /dev/null @@ -1,676 +0,0 @@ -ngcp-prosody-modules (14.1.0.0+0~mr14.1.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 24 Nov 2025 16:57:25 +0100 - -ngcp-prosody-modules (14.0.0.0+0~mr14.0.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 08 Sep 2025 11:45:56 +0200 - -ngcp-prosody-modules (13.5.0.0+0~mr13.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Fri, 20 Jun 2025 10:44:56 +0200 - -ngcp-prosody-modules (13.4.0.0+0~mr13.4.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Thu, 10 Apr 2025 08:29:21 +0200 - -ngcp-prosody-modules (13.3.0.0+0~mr13.3.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 28 Jan 2025 15:15:59 +0100 - -ngcp-prosody-modules (13.2.0.0+0~mr13.2.0.0) unstable; urgency=medium - - [ Richard Fuchs ] - * [01bb8cb] MT#53790 pushd: rename `gcm` to `fcm` - - -- Sipwise Jenkins Builder Mon, 09 Dec 2024 11:28:18 +0100 - -ngcp-prosody-modules (13.1.0.0+0~mr13.1.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 01 Oct 2024 10:01:17 +0200 - -ngcp-prosody-modules (13.0.0.0+0~mr13.0.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Sun, 28 Jul 2024 12:04:04 +0200 - -ngcp-prosody-modules (12.5.0.0+0~mr12.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Wed, 22 May 2024 14:32:48 +0200 - -ngcp-prosody-modules (12.4.0.0+0~mr12.4.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Fri, 15 Mar 2024 08:49:29 +0100 - -ngcp-prosody-modules (12.3.0.0+0~mr12.3.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 15 Jan 2024 14:48:24 +0100 - -ngcp-prosody-modules (12.2.0.0+0~mr12.2.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Wed, 29 Nov 2023 13:38:06 +0100 - -ngcp-prosody-modules (12.1.0.0+0~mr12.1.0.0) unstable; urgency=medium - - [ Guillem Jover ] - * [bef0870] MT#58356 Update packaging for bookworm - - [ Victor Seva ] - * [6957e9c] MT#58471 refresh modules - - [ Marco Capetta ] - * [02a6ec0] MT#58471 Fix mod_carbons_adhoc call to adhoc module - - -- Sipwise Jenkins Builder Sun, 15 Oct 2023 08:25:07 +0200 - -ngcp-prosody-modules (12.0.1.0+0~mr12.0.1.0) unstable; urgency=medium - - [ Mykola Malkov ] - * [29dbb14] MT#57453 Switch docker image to bookworm - - -- Sipwise Jenkins Builder Wed, 30 Aug 2023 18:05:32 +0200 - -ngcp-prosody-modules (11.5.0.0+0~mr11.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 26 Jun 2023 14:11:45 +0200 - -ngcp-prosody-modules (11.4.0.0+0~mr11.4.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Fri, 24 Mar 2023 13:05:07 +0100 - -ngcp-prosody-modules (11.3.0.0+0~mr11.3.0.0) unstable; urgency=medium - - [ Michael Prokop ] - * [0fac3f5] MT#55819 MT#55524 Depend on either lua-rex-pcre or lua-rex-pcre2 - - [ Victor Seva ] - * [50c3253] MT#55920 Support rex_pcre2 with Debian/bookworm - - -- Sipwise Jenkins Builder Tue, 17 Jan 2023 17:44:38 +0100 - -ngcp-prosody-modules (11.2.0.0+0~mr11.2.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 04 Oct 2022 13:52:12 +0200 - -ngcp-prosody-modules (11.1.0.0+0~mr11.1.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 22 Aug 2022 20:02:57 +0200 - -ngcp-prosody-modules (11.0.0.0+0~mr11.0.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 07 Jun 2022 11:45:14 +0200 - -ngcp-prosody-modules (10.5.0.0+0~mr10.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Thu, 31 Mar 2022 00:01:48 +0200 - -ngcp-prosody-modules (10.4.0.0+0~mr10.4.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 24 Jan 2022 16:57:42 +0100 - -ngcp-prosody-modules (10.3.0.0+0~mr10.3.0.0) unstable; urgency=medium - - [ Guillem Jover ] - * [2080a38] TT#124273 Update packaging for bullseye - * [13049ba] TT#124273 Move override_dh_auto_clean actions into debian/clean - * [b8e90ca] TT#124273 Use execute_after_ instead of override_ for dh command - - [ Victor Seva ] - * [1511c9a] TT#150950 sipwise_pushd: support new mobile_push_enable values - * [6ae871f] TT#150950 sipwise_pushd: don't need to check dom preferences - - -- Sipwise Jenkins Builder Tue, 23 Nov 2021 14:19:49 +0100 - -ngcp-prosody-modules (10.2.0.0+0~mr10.2.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [45c42ff] TT#137602 vhost_sql: prepare host from sql - * [a7e1cd5] TT#137602 auth_sql: lower domain for comparation - - -- Sipwise Jenkins Builder Tue, 05 Oct 2021 13:20:47 +0200 - -ngcp-prosody-modules (10.1.0.0+0~mr10.1.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 24 Aug 2021 16:53:07 +0200 - -ngcp-prosody-modules (10.0.0.0+0~mr10.0.0.0) unstable; urgency=medium - - [ Manuel Montecelo ] - * [5f829f3] TT#118659 Switch Dockerfile from Debian buster to bullseye - - -- Sipwise Jenkins Builder Mon, 14 Jun 2021 16:38:22 +0200 - -ngcp-prosody-modules (9.5.0.0+0~mr9.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 20 Apr 2021 11:59:27 +0200 - -ngcp-prosody-modules (9.4.0.0+0~mr9.4.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 15 Feb 2021 17:54:21 +0100 - -ngcp-prosody-modules (9.3.0.0+0~mr9.3.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 05 Jan 2021 15:33:09 +0100 - -ngcp-prosody-modules (9.2.0.0+0~mr9.2.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [181deaf] TT#92952 sipwise_pushd: fix mobile_push_silent_list query - * [4b1b193] TT#96550 mod_sipwise_redis_*: add some more debug info at add_host() - * [e7ecca6] TT#15822 mod_sipwise_pushd: fix error introduced back in 2017 - * [addb5e5] TT#97400 sipwise_vhosts_sql: fix [de]activation of vhost via ngcp-panel - * [2cee084] TT#99900 remove utils/table.lua and use the one from lua-ngcp-kamailio - * [dde6a2f] TT#96550 mod_muc interface changed since 0.11.0 - - -- Sipwise Jenkins Builder Mon, 09 Nov 2020 16:26:34 +0100 - -ngcp-prosody-modules (9.1.0.0+0~mr9.1.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 31 Aug 2020 21:55:41 +0200 - -ngcp-prosody-modules (9.0.0.0+0~mr9.0.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 21 Jul 2020 14:49:26 +0200 - -ngcp-prosody-modules (8.6.0.0+0~mr8.6.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 14 Jul 2020 11:54:14 +0200 - -ngcp-prosody-modules (8.5.0.0+0~mr8.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 19 May 2020 11:11:46 +0200 - -ngcp-prosody-modules (8.4.0.0+0~mr8.4.0.0) unstable; urgency=medium - - [ Richard Fuchs ] - * [06bdfa9] TT#20350 mod_auth_sql: check subscriber lock level - - -- Sipwise Jenkins Builder Mon, 16 Mar 2020 11:17:03 +0100 - -ngcp-prosody-modules (8.3.0.0+0~mr8.3.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [0f25a1c] TT#72257 refresh plugins from upstream - * [34e3345] TT#35053 remove mod_mam patch for sipwise_archive.lib - * [4fb063d] TT#66583 remove modules merged at prosody 0.11 version - * [937d0dd] TT#66583 remove patch for own module - * [f9b0c6f] TT#66583 fix load module error - * [157f5fe] TT#66583 changes needed for support 0.11 - * [a1721ca] TT#66583 remove unussed mod_sipwise_offline - - [ Alexander Lutay ] - * [731a058] TT#66583 Add util/prosody_sipwise_migrator for upgrade to prosody 0.11 - - -- Sipwise Jenkins Builder Mon, 27 Jan 2020 12:25:14 +0100 - -ngcp-prosody-modules (8.2.0.0+0~mr8.2.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 25 Nov 2019 14:58:26 +0100 - -ngcp-prosody-modules (8.1.0.0+0~mr8.1.0.0) unstable; urgency=medium - - [ Manuel Montecelo ] - * [5c9c265] Revert "TT#44917 Ship certain modules only on Debian/stretch" - * [3f09215] TT#66582 Change the dependency on prosody, it does not work with later versions - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Tue, 08 Oct 2019 09:11:47 +0200 - -ngcp-prosody-modules (8.0.0.0+0~mr8.0.0.0) unstable; urgency=medium - - [ Alexander Lutay ] - * [b898a6c] TT#60950 Switch prosody docker to buster - - [ Guillem Jover ] - * [9cbd440] TT#61954 Add missing COPYING file from upstream - * [c873da3] TT#61954 Update copyright Format URL to use https - * [22a5ddd] TT#61954 Rework debian/copyright file - * [4211f6d] TT#61954 Update copyright years - * [3ab509e] TT#61954 Set debhelper compat level in Build-Depends instead of debian/compat - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 05 Aug 2019 20:59:38 +0200 - -ngcp-prosody-modules (7.5.0.0+0~mr7.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 17 Jun 2019 14:39:21 +0200 - -ngcp-prosody-modules (7.4.0.0+0~mr7.4.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Thu, 25 Apr 2019 14:31:30 +0200 - -ngcp-prosody-modules (7.3.0.0+0~mr7.3.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 25 Feb 2019 22:58:44 +0100 - -ngcp-prosody-modules (7.2.0.0+0~mr7.2.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Wed, 09 Jan 2019 22:03:22 +0100 - -ngcp-prosody-modules (7.1.0.0+0~mr7.1.0.0) unstable; urgency=medium - - [ Michael Prokop ] - * [039086e] TT#44917 Ship certain modules only on Debian/stretch - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 12 Nov 2018 22:39:48 +0100 - -ngcp-prosody-modules (7.0.0.0+0~mr7.0.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 24 Sep 2018 18:58:25 +0200 - -ngcp-prosody-modules (6.5.0.0+0~mr6.5.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Tue, 24 Jul 2018 13:40:44 +0200 - -ngcp-prosody-modules (6.4.0.0+0~mr6.4.0.0) unstable; urgency=medium - - [ Andreas Granig ] - * [a0418df] TT#35053 Fix MAM by retrieving also inbound msg - * [fde6324] TT#35604 Implement silent flag for push - - [ Guillem Jover ] - * [c17d295] TT#26264 Remove maintainer script directly calling init scripts - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Tue, 29 May 2018 10:09:00 +0200 - -ngcp-prosody-modules (6.3.0.0+0~mr6.3.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [b84c7b3] [util/table] fix implode function - * [dd76b25] TT#33379 Merge https://github.com/sipwise/prosody/pull/2 - - [ Andreas Granig ] - * [5784273] TT#27653 Strip trailing trash from uuid - - [ Richard Fuchs ] - * [bffc901] TT#34705 merge https://github.com/sipwise/prosody/pull/3 - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Tue, 03 Apr 2018 22:32:05 +0200 - -ngcp-prosody-modules (6.2.0.0+0~mr6.2.0.0) unstable; urgency=medium - - [ Sergii Kipot ] - * [cd32e76] TT#29456 Create prosody-jessie docker for luacheck - * [48fbebb] TT#29456 Create prosody-stretch docker for luacheck - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 29 Jan 2018 21:56:46 +0100 - -ngcp-prosody-modules (6.1.0.0+0~mr6.1.0.0) unstable; urgency=medium - - [ Guillem Jover ] - * [a6fa2c1] TT#22072 Update packaging - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Wed, 06 Dec 2017 00:13:15 +0100 - -ngcp-prosody-modules (6.0.0.0+0~mr6.0.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Mon, 02 Oct 2017 23:43:33 +0200 - -ngcp-prosody-modules (5.5.0.0+0~mr5.5.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [1057e3a] TT#17657 mod_sipwise_pushd: send full_message field to pushd - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 17 Jul 2017 22:47:07 +0200 - -ngcp-prosody-modules (5.4.0.0+0~mr5.4.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [fb99302] TT#13055 mod_sipwise_pushd: support muc_config - * [5b993fc] TT#14103 update upstream modules to 2e1a4740adee - * [0117591] TT#14278 mam: add all supported versions to disco - * [d6f87e7] TT#14258 mod_sipwise_pushd: add nick attribute for MUC presence - * [23e737f] TT#15822 mod_sipwise_pushd: detect attachment message - * [ef87c7b] TT#14103 update upstream modules to 9b43b7fc3558 - * [a70b099] TT#16400 support exclude config muc rooms from sending push notifications - - [ Andreas Granig ] - * [0521a03] TT#14099 Send muc room name in push - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Tue, 16 May 2017 21:43:06 +0200 - -ngcp-prosody-modules (5.3.0.0+0~mr5.3.0.0) unstable; urgency=medium - - * New release. - - -- Sipwise Jenkins Builder Wed, 22 Mar 2017 11:00:59 +0100 - -ngcp-prosody-modules (5.2.0.0+0~mr5.2.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [c52d6cd] MT#16059 mod_sipwise_vhosts_sql: fix debug output - * [bb1360f] TT#7560 mod_sipwise_offline - * [9e65f10] TT#7482 mod_man: support mam version 0.5 (urn:xmpp:mam:1) - * [754fb5b] TT#8297 mam: implement archive to DB - * [c2dec69] TT#8766 mod_sipwise_pushd: fix error when caller is not from local domain - * [9e93fb6] TT#9303 mod_mam: sipwise_archive.lib fix crash at find() - * [b17aec9] TT#9311 mod_mam/sipwise_archive.lib: full username - * [7fc4d61] TT#9317 mod_mam: don't store bodyless chat messages - * [0fbc57e] TT#9400 use quilt to maintain patches to upstream - * [e191475] TT#9402 refresh modules from upstream - * [11f3f0b] TT#9504 sipwise_offline: do not store bodyless chat messages - * [d5491e2] TT#9503 sipwise_pushd: wrong offline badge - * [937ff0f] TT#9314: support emojis for DB - * [ff4c2e0] TT#9551 set charset on reconnection - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Fri, 03 Feb 2017 00:41:42 +0100 - -ngcp-prosody-modules (5.1.0.0+0~mr5.1.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [e4a378a] MT#10921 add mod_man plugin - * [5003261] TT#6605 mod_sipwise_pushd: fix MUC offline when sender has more than one session - * [0d7e7ac] TT#6646 support XEP-0352: Client State Indication - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Thu, 17 Nov 2016 23:19:59 +0100 - -ngcp-prosody-modules (5.0.0.0+0~mr5.0.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [b09f209] MT#19579 pushd: define get_muc_room() to filter possible errors - - -- Alexander Lutay Fri, 21 Oct 2016 15:18:37 +0200 - -ngcp-prosody-modules (1.15.0.0+0~mr5.0.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [608b9d6] MT#20021 mod_sipwise_vjud: add some debug messages related to normalize_number and search_by_number - * [bc610ad] Revert "MT#18055 mod_sipwise_vjud: use dataforms for searching e164 values" - * [9b811d4] MT#18055 mod_sipwise_vjud: use dataforms for searching e164 values - * [778b400] TT#1597 sipwise_vjud: add domain field - * [12c628f] TT#1597 sipwise_vjud: fix dataform reply format - * [c51c1f6] TT#1597 sipwise_vjud: fix dataform reply format - - [ Guillem Jover ] - * [4a32147] MT#20479 Fix the package to be architecture all - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 01 Aug 2016 16:35:39 +0200 - -ngcp-prosody-modules (1.14.0.0+0~mr4.5.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [5181464] MT#18725 mod_sipwise_groups: reconnect_check for lookup functions - * [b83138c] MT#18905 support pushd_blocking - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 23 May 2016 19:00:19 +0200 - -ngcp-prosody-modules (1.13.0.0+0~mr4.4.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [dad9a2c] MT#17545 upgrade community modules - * [9474448] MT#17541 support XEP-191 mod_blocking - * [c122e4e] MT#18041 mod_sipwise_vjud: fix discovery - * [f6031ab] MT#18041 mod_sipwise_vjud: fix discovery, clean code - * [32cbf31] MT#18055 mod_sipwise_vjud: use dataforms for searching e164 values - - [ Michael Prokop ] - * [aa5ffbc] MT#17699 Bump Standards-Version to 3.9.7 - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 21 Mar 2016 22:29:16 +0100 - -ngcp-prosody-modules (1.12.0.0+0~mr4.3.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [ff763a7] MT#15837 mod_sipwise_vcard_cusax: add error when no info is retrive - * [24c1cc4] MT#15893 mod_sipwise_vcard_cusax: return error if subscriber does not exist - * [bbb6f0f] MT#15819 mod_sipwise_pushd: set apns_alert message on muc - * [c5f0784] MT#6407 cluster using mod_shard* as base - * [babc44f] MT#6407 support MUC on cluster - * [320bdef] MT#16059 save MUC participants on redis too - * [8243371] MT#16059 mod_sipwise_redis_mucs: fix unbind hook. fixes commit 320bdefb33c - * [d346079] MT#16059 mod_sipwise_pushd: support groupchat messages - * [a943438] MT#15893 mod_sipwise_vcard_cusax: fix error if domain has no users - * [c579c89] MT#16059 mod_sipwise_vhosts_sql: fix load sipwise_vjud component at search domain - * [7e27dba] MT#16059 mod_sipwise_vjud: fix load module - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Wed, 16 Dec 2015 09:30:28 +0100 - -ngcp-prosody-modules (1.11.0.0+0~mr4.2.0.0) unstable; urgency=medium - - [ Victor Seva ] - * [d20b62f] MT#14281 pushd: use formencode() in order to urlencode the http request - * [ee207e5] MT#14293 luacheck project config - * [be8663b] MT#14921 add uuid push_id parameter - * [6abfd0f] MT#15119 sipwise_log_debug module - * [f672d8e] MT#15303 add mod_limit_auth - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 12 Oct 2015 15:43:59 +0200 - -ngcp-prosody-modules (1.10.0.0+0~mr4.1.0.0) unstable; urgency=low - - [ Victor Seva ] - * [5a87e97] MT#8951 fix vcard format v2 and email - * [d55bd7e] MT#11583 lastactivity: fix debug output and remove .save() .restore() - * [d08c713] MT#12267 merge changes from 0.9.8 - * [8447071] MT#12267 add mod_carbons and sync mod_smacks - * [e2ae328] MT#12267 add mod_carbons_* and sync mod_smacks ( license header ) - * [1e3496f] MT#12953 pushd: fix error when the user is not provided properly - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 13 Jul 2015 15:32:17 +0200 - -ngcp-prosody-modules (1.9.0.0+0~mr4.0.0.0) unstable; urgency=low - - [ Victor Seva ] - * [7780d3c] MT#10849: add mod_smacks plugin - * [aae45da] MT#6411 redis_session: new key schema - * [3f2c23f] MT#6407 prosody cluster - * [5021516] MT#9763 pushd: add prefix with sender_name at apns_alert field - * [73fde6c] MT#9763 pushd: set the push msg for muc invitations - * [af940bf] MT#6407 mod_sipwise_cluster: remove unused host config - * [f1631d6] MT#9763 pushd: fix get_caller_info() - * [26c11e6] MT#11125 don't restart prosody after install if node is not proxy - * [c4633d8] MT#11125 fix bashism at 26c11e6e3841a. Don't restart prosody after install if node is not proxy - * [a017dbf] MT#11583 add our own lastactivity module - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Wed, 18 Mar 2015 14:12:57 +0100 - -ngcp-prosody-modules (1.8.0.0+0~mr3.8.0.0) unstable; urgency=low - - [ Victor Seva ] - * [f031997] MT#9985 vhosts: enable MUC for domains - * [7945b1b] MT#9985 vhosts: rework enable MUC for domains - * [6dfa707] MT#9763 pushd: extended gcm and aspn parameters. - * [dd8da8e] MT#7141 upgrade package to 3.0 style - * [a6e0655] MT#9763 Pushd: use new format for pushd query. Skip empty messages - * [d4995ce] MT#9763 push: add data_sender_number and data_sender_sip - - [ Alexander Lutay ] - * [5914b4f] MT#9763 Pushd: updated Apple sound files + typo fix s/aspn/apns/ - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Wed, 07 Jan 2015 21:37:29 +0100 - -ngcp-prosody-modules (1.7.0.0+0~mr3.7.0.0) unstable; urgency=low - - * New release. - - -- Sipwise Jenkins Builder Thu, 30 Oct 2014 17:29:07 +0100 - -ngcp-prosody-modules (1.6.0.0+0~mr3.6.0.0) unstable; urgency=low - - [ Victor Seva ] - * [0d82202] MT#8851 add mod_sipwise_pushd module - * [c84cc7e] MT#7505 add .gitreview file - * [2c0bf78] MT#8951 sipwise_vcard_cusax: add numbers, name and email - * [31fb42e] MT#8951 fix vcard format and querys - * [963cfd4] MT#8851 mod_sipwise_pushd: fix 0d8220219aeb2 domain query - * [4201b42] MT#8851 mod_sipwise_pushd: fix 0d8220219aeb2 domain query call - * [39e4b7d] MT#8851 pushd: use from info when available if origin is null - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Thu, 09 Oct 2014 16:52:28 +0200 - -ngcp-prosody-modules (1.5.0.0+0~mr3.5.0.0) unstable; urgency=low - - [ Victor Seva ] - * [f9d8739] MT#7545 Adapt queries to the new voip_pbx_groups schema. - * [9a736c5] MT#6431 restart prosody service after instalation - * [a02bb76] MT#7545 remove pilot from the list of subscribers - * [fce80c1] MT#6431 fix postinst script if node is not active - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Thu, 10 Jul 2014 15:35:26 +0200 - -ngcp-prosody-modules (1.4.0.0+0~mr3.4.0.0) unstable; urgency=low - - [ Victor Seva ] - * [47678b7] MT#6285 add mod_log_auth plugin - - [ Sipwise Jenkins Builder ] - - -- Sipwise Jenkins Builder Mon, 26 May 2014 15:58:51 +0200 - -ngcp-prosody-modules (1.3.0.0+0~mr3.3.0.0) unstable; urgency=low - - [ Victor Seva ] - * [47f488b] Add licence note on source files - * [8dd77ca] MT#6409 Create mod_sipwise_admin_telnet - * [f4cef17] MT#6411 Add mod_sipwise_redis_sessions module. - * [efb226e] MT#6285 add mod_log_auth plugin - * [f53d100] MT#7053 add database name to the queries. Use auth_sql prosody config. - - [ Michael Prokop ] - * [80bcd45] MT#6511 Bump Standards-Version to 3.9.5 - - -- Alexander Lutay Wed, 14 May 2014 11:10:31 +0200 - -ngcp-prosody-modules (1.2.0.0+0~mr3.3.0.0) unstable; urgency=low - - [ Andreas Granig ] - * [68fb4e4] MT#5811 Add xmpp-over-websocket plugin. - - -- Alexander Lutay Fri, 21 Mar 2014 15:42:58 +0100 - -ngcp-prosody-modules (1.1.0) unstable; urgency=low - - [ Victor Seva ] - * [09d8ccd] Initial version of sipwise_groups module. - - [ Andreas Granig ] - * [c71c975] Update copyright to cover all files. - - -- Victor Seva Tue, 29 Oct 2013 14:59:54 +0100 - -ngcp-prosody-modules (1.0.1) unstable; urgency=low - - * [dea7650] Implicitely add domain with "search" prefix. - - -- Andreas Granig Thu, 08 Aug 2013 00:03:08 +0200 - -ngcp-prosody-modules (1.0.0) unstable; urgency=low - - * [804143c] Remove authentication by number. - * [28b5fc5] Implement XEP-0055 with implicit rewrite rules. - - -- Andreas Granig Wed, 07 Aug 2013 22:38:07 +0200 - -ngcp-prosody-modules (0.0.1) unstable; urgency=low - - * Initial release - - -- Michael Prokop Tue, 02 Jul 2013 01:54:04 +0200 - diff --git a/debian/clean b/debian/clean deleted file mode 100644 index 2967547..0000000 --- a/debian/clean +++ /dev/null @@ -1 +0,0 @@ -debian/README_mod_*.* diff --git a/debian/control b/debian/control deleted file mode 100644 index c0f2daf..0000000 --- a/debian/control +++ /dev/null @@ -1,58 +0,0 @@ -Source: ngcp-prosody-modules -Section: net -Priority: optional -Maintainer: Sipwise Development Team -Homepage: https://www.sipwise.com/ -Standards-Version: 4.6.2 -Rules-Requires-Root: no -Build-Depends: - debhelper-compat (= 13), - quilt, - -Package: ngcp-prosody-modules -Architecture: all -Depends: - lua-bitop, - lua-dbi-common, - lua-dbi-mysql, - lua-ngcp-kamailio, - lua-redis, - lua-rex-pcre | lua-rex-pcre2, - lua-sec, - lua5.2, - prosody (>= 0.11~), - ${misc:Depends}, -Description: ngcp modules for the prosody Jabber/XMPP server - This package provides modules for the Prosody Jabber/XMPP server - Prosody, especially for usage with the Sipwise Next Generation - Communication Platform. - . - The following modules are available: - . - * mod_sipwise_admin_telnet: admin_telnet with inteface selection - * mod_sipwise_groups.lua: inserts PBX groups to the user contact list - * mod_sipwise_lastactivity: XEP-0012 - * mod_sipwise_pushd: push notification to mobile users - * mod_sipwise_redis_sessions: keep server's session info on redis - * mod_sipwise_vcard_cusax.lua: return a vcard containing SIP URIs for - phone/video of the requested user - * mod_sipwise_vhosts_sql.lua: load vhosts from DB on startup of Prosody - XMPP server - * mod_sipwise_vjud.lua: implement Jabber Search with implicit number - normalization using the NGCP rewrite rules - . - The following modules are from prosody-modules: - . - * mod_auth_sql.lua: simple SQL Authentication module - * mod_blocking: allows the client to manage a simple - list of blocked JIDs - * mod_carbons_adhoc - * mod_carbons_copies - * mod_filter_chatstates: will filter Chat State Notifications out - while the session is considered inactive - * mod_limit_auth: lets you put a per-IP limit on the number of - failed authentication attempts - * mod_log_auth: logs IP address in a failed authentication attempt - * mod_smacks: XEP-0198: Stream Management - * mod_throttle_presence: cuts down on presence traffic when clients - indicate they are inactive diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 48222d3..0000000 --- a/debian/copyright +++ /dev/null @@ -1,98 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Source: https://www.sipwise.com/ -Upstream-Name: ngcp-prosody -Upstream-Contact: Sipwise GmbH - -Files: - * -Copyright: - 2013-2023 Sipwise GmbH, Austria -License: MIT - -Files: - plugins/mod_auth_sql.lua -Copyright: - 2011 Tomasz Sterna - 2011 Waqas Hussain - 2013-2023 Sipwise GmbH, Austria -License: MIT - -Files: - plugins/mod_sipwise_vcard_cusax.lua -Copyright: - 2008-2010 Matthew Wild - 2008-2010 Waqas Hussain - 2013-2023 Sipwise GmbH, Austria -License: MIT - -Files: - plugins/mod_carbons.lua -Copyright: - 2011 Kim Alvefur -License: MIT - -Files: - plugins/mod_carbons_copies.lua -Copyright: - 2012 Michael Holzt - 2014 Florian Zeitz -License: MIT - -Files: - plugins/mod_carbons_adhoc.lua -Copyright: - 2012 Michael Holzt - 2014 Florian Zeitz -License: MIT - -Files: - plugins/mod_sipwise_lastactivity.lua -Copyright: - 2008-2010 Matthew Wild - 2008-2010 Waqas Hussain - 2015-2023 Sipwise GmbH, Austria -License: MIT - -Files: - plugins/mod_log_auth.lua -Copyright: - 2013 Kim Alvefur -License: MIT - -Files: - plugins/mod_smacks.lua -Copyright: - 2010-2015 Matthew Wild - 2010 Waqas Hussain - 2012-2015 Kim Alvefur - 2012 Thijs Alkemade - 2014 Florian Zeitz -License: MIT - -Files: - plugins/mod_blocking.lua -Copyright: - 2010-2015 Kim Alvefur - 2013 Tobias Markmann - 2011 Paul Aurich - 2010 Waqas Hussain - 2010 Matthew Wild -License: MIT - -License: MIT - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - . - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - . - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/debian/ngcp-prosody-modules.docs b/debian/ngcp-prosody-modules.docs deleted file mode 100644 index 547bb7b..0000000 --- a/debian/ngcp-prosody-modules.docs +++ /dev/null @@ -1 +0,0 @@ -debian/README_mod* diff --git a/debian/ngcp-prosody-modules.install b/debian/ngcp-prosody-modules.install deleted file mode 100644 index 0c09054..0000000 --- a/debian/ngcp-prosody-modules.install +++ /dev/null @@ -1,2 +0,0 @@ -plugins/* /usr/lib/prosody/modules/ -util/* /usr/lib/prosody/util/ diff --git a/debian/patches/fix_mod_carbons_adhoc_call_to_adhoc.patch b/debian/patches/fix_mod_carbons_adhoc_call_to_adhoc.patch deleted file mode 100644 index a229855..0000000 --- a/debian/patches/fix_mod_carbons_adhoc_call_to_adhoc.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Sipwise Development Team -Date: Wed, 11 Oct 2023 09:52:08 +0200 -Subject: fix_mod_carbons_adhoc_call_to_adhoc - -Change-Id: If2ce4cf8dff63c3a8491845d76f0b33b472dc8b6 ---- - plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua b/plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua -index 406a0b0..e8af962 100644 ---- a/plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua -+++ b/plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua -@@ -35,6 +35,6 @@ local function adhoc_status(self, data, state) - end - - local status_desc = adhoc_new("Carbons: Get Status", -- "mod_carbons_adhoc#status", adhoc_status); -+ "mod_carbons_adhoc#status", adhoc_status, 'any'); - - module:add_item("adhoc", status_desc); diff --git a/debian/patches/mod_auth_sql.path b/debian/patches/mod_auth_sql.path deleted file mode 100644 index 6c0241a..0000000 --- a/debian/patches/mod_auth_sql.path +++ /dev/null @@ -1,37 +0,0 @@ -From: Andreas Granig -Date: Wed, 7 Aug 2013 22:34:34 +0200 -Subject: sipwise custom auth - ---- - plugins/mod_auth_sql/mod_auth_sql.lua | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/plugins/mod_auth_sql/mod_auth_sql.lua b/plugins/mod_auth_sql/mod_auth_sql.lua -index 2947a91..631768d 100644 ---- a/plugins/mod_auth_sql/mod_auth_sql.lua -+++ b/plugins/mod_auth_sql/mod_auth_sql.lua -@@ -71,10 +71,13 @@ local function getsql(sql, ...) - end - - local function get_password(username) -- local stmt, err = getsql("SELECT `password` FROM `authreg` WHERE `username`=? AND `realm`=?", username, module.host); -+ local stmt, err = getsql("SELECT `s`.`password`, COALESCE(`p`.`value`, 0) AS `locklevel` FROM `subscriber` AS `s` LEFT JOIN usr_preferences AS `p` ON `p`.`username` = `s`.`username` AND `p`.`domain` = `s`.`domain` AND `p`.`attribute` = 'lock' WHERE `s`.`username`= ? AND lower(`s`.`domain`)= ?", username, module.host); - if stmt then - for row in stmt:rows(true) do -- return row.password; -+ local locklevel = 0 + row.locklevel; -+ if locklevel < 4 then -+ return row.password; -+ end - end - end - end -@@ -109,7 +112,7 @@ function provider.get_sasl_handler() - end - - function provider.users() -- local stmt, err = getsql("SELECT `username` FROM `authreg` WHERE `realm`=?", module.host); -+ local stmt, err = getsql("SELECT `username` FROM `subscriber` WHERE lower(`domain`)=?", module.host); - if stmt then - local next, state = stmt:rows(true) - return function() diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 6e245b8..0000000 --- a/debian/patches/series +++ /dev/null @@ -1,2 +0,0 @@ -mod_auth_sql.path -fix_mod_carbons_adhoc_call_to_adhoc.patch diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 50f855e..0000000 --- a/debian/rules +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/make -f -# Uncomment this to turn on verbose mode. -# export DH_VERBOSE=1 - -%: - dh $@ --with quilt - -override_dh_auto_configure: - while read module ; do \ - if [ -f plugins/$$module/README.markdown ] ; then \ - cp plugins/$$module/README.markdown debian/README_$$module.markdown; \ - fi; \ - done < prosody-modules.list; \ - -execute_after_dh_install: - find debian/ngcp-prosody-modules/ -name README.\* -delete diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 89ae9db..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/plugins/mod_auth_sql/README.markdown b/plugins/mod_auth_sql/README.markdown deleted file mode 100644 index 31485d1..0000000 --- a/plugins/mod_auth_sql/README.markdown +++ /dev/null @@ -1,40 +0,0 @@ ---- -labels: -- 'Type-Auth' -- 'Stage-Stable' -summary: SQL Database authentication module -... - -Introduction -============ - -Allow client authentication to be handled by an SQL database query. - -Unlike mod\_storage\_sql (which is supplied with Prosody) this module -allows for custom schemas (though currently it is required to edit the -source). - -Configuration -============= - -As with all auth modules, there is no need to add this to -modules\_enabled. Simply add in the global section, or for the relevant -hosts: - - authentication = "sql" - -This module reuses the database configuration of -[mod\_storage\_sql](http://prosody.im/doc/modules/mod_storage_sql) (the -'sql' option), which you can set even if you are not using SQL as -Prosody's primary storage backend. - -The query is currently hardcoded in the module, so you will need to edit -the module to change it. The default query is compatible with jabberd2 -DB schema. - -Compatibility -============= - - ----- ------- - 0.8 Works - ----- ------- diff --git a/plugins/mod_auth_sql/mod_auth_sql.lua b/plugins/mod_auth_sql/mod_auth_sql.lua deleted file mode 100644 index 2947a91..0000000 --- a/plugins/mod_auth_sql/mod_auth_sql.lua +++ /dev/null @@ -1,125 +0,0 @@ --- Simple SQL Authentication module for Prosody IM --- Copyright (C) 2011 Tomasz Sterna --- Copyright (C) 2011 Waqas Hussain --- - -local log = require "util.logger".init("auth_sql"); -local new_sasl = require "util.sasl".new; -local DBI = require "DBI" - -local connection; -local params = module:get_option("auth_sql", module:get_option("sql")); - -local resolve_relative_path = require "core.configmanager".resolve_relative_path; - -local function test_connection() - if not connection then return nil; end - if connection:ping() then - return true; - else - module:log("debug", "Database connection closed"); - connection = nil; - end -end -local function connect() - if not test_connection() then - prosody.unlock_globals(); - local dbh, err = DBI.Connect( - params.driver, params.database, - params.username, params.password, - params.host, params.port - ); - prosody.lock_globals(); - if not dbh then - module:log("debug", "Database connection failed: %s", tostring(err)); - return nil, err; - end - module:log("debug", "Successfully connected to database"); - dbh:autocommit(true); -- don't run in transaction - connection = dbh; - return connection; - end -end - -do -- process options to get a db connection - params = params or { driver = "SQLite3" }; - - if params.driver == "SQLite3" then - params.database = resolve_relative_path(prosody.paths.data or ".", params.database or "prosody.sqlite"); - end - - assert(params.driver and params.database, "Both the SQL driver and the database need to be specified"); - - assert(connect()); -end - -local function getsql(sql, ...) - if params.driver == "PostgreSQL" then - sql = sql:gsub("`", "\""); - end - if not test_connection() then connect(); end - -- do prepared statement stuff - local stmt, err = connection:prepare(sql); - if not stmt and not test_connection() then error("connection failed"); end - if not stmt then module:log("error", "QUERY FAILED: %s %s", err, debug.traceback()); return nil, err; end - -- run query - local ok, err = stmt:execute(...); - if not ok and not test_connection() then error("connection failed"); end - if not ok then return nil, err; end - - return stmt; -end - -local function get_password(username) - local stmt, err = getsql("SELECT `password` FROM `authreg` WHERE `username`=? AND `realm`=?", username, module.host); - if stmt then - for row in stmt:rows(true) do - return row.password; - end - end -end - - -provider = {}; - -function provider.test_password(username, password) - return password and get_password(username) == password; -end -function provider.get_password(username) - return get_password(username); -end -function provider.set_password(username, password) - return nil, "Setting password is not supported."; -end -function provider.user_exists(username) - return get_password(username) and true; -end -function provider.create_user(username, password) - return nil, "Account creation/modification not supported."; -end -function provider.get_sasl_handler() - local profile = { - plain = function(sasl, username, realm) - local password = get_password(username); - if not password then return "", nil; end - return password, true; - end - }; - return new_sasl(module.host, profile); -end - -function provider.users() - local stmt, err = getsql("SELECT `username` FROM `authreg` WHERE `realm`=?", module.host); - if stmt then - local next, state = stmt:rows(true) - return function() - for row in next, state do - return row.username; - end - end - end - return stmt, err; -end - - -module:provides("auth", provider); diff --git a/plugins/mod_blocking/README.markdown b/plugins/mod_blocking/README.markdown deleted file mode 100644 index 21b2a26..0000000 --- a/plugins/mod_blocking/README.markdown +++ /dev/null @@ -1,54 +0,0 @@ ---- -labels: -- 'Stage-Alpha' -summary: 'XEP-0191: Simple Communications Blocking support' -... - -Introduction -============ - -Privacy lists are a widely implemented protocol for instructing your -server on blocking communications with selected users and services. - -However experience has shown that the power and flexibility of the -rule-based system that privacy lists allow is very often much more -complex than the user needs, and that in most cases a simple block on -all communications to or from a list of specified JIDs would suffice. - -Such a protocol would also allow much simpler user interface design than -the current attempts at full privacy list interfaces. - -Details -======= - -Simple Communications Blocking was developed to solve the above issues, -and allows the client to manage a simple list of blocked JIDs. This -plugin implements support for that protocol in Prosody, however the -actual blocking is still managed by mod\_privacy, so it is **required** -for that plugin to be loaded (this may change in future). - -An XEP-0191 implementation without dependency on mod\_privacy is -available in Prosody 0.10 as [mod\_blocklist][doc:modules:mod_blocklist]. - -Configuration -============= - -Simply ensure that mod\_privacy (or [mod\_privacy\_lists] in 0.10+) and -mod\_blocking are loaded in your modules\_enabled list: - - modules_enabled = { - -- ... - "privacy", -- or privacy_lists in Prosody 0.10+ - "blocking", - -- ... - -Compatibility -============= - - ------ --------------------------------------------- - 0.10 Works but will conflict with mod\_blocklist - 0.9 Works - 0.8 Works - 0.7 Works - 0.6 Doesn't work - ------ --------------------------------------------- diff --git a/plugins/mod_blocking/mod_blocking.lua b/plugins/mod_blocking/mod_blocking.lua deleted file mode 100644 index 092de6f..0000000 --- a/plugins/mod_blocking/mod_blocking.lua +++ /dev/null @@ -1,173 +0,0 @@ -local jid_split = require "util.jid".split; -local st = require "util.stanza"; -local datamanager = require"util.datamanager"; - -local xmlns_blocking = "urn:xmpp:blocking"; - -module:add_feature("urn:xmpp:blocking"); - --- Add JID to default privacy list -function add_blocked_jid(username, host, jid) - local privacy_lists = datamanager.load(username, host, "privacy") or {lists = {}}; - local default_list_name = privacy_lists.default; - if not privacy_lists.lists then - privacy_lists.lists = {} - end - if not default_list_name then - default_list_name = "blocklist"; - privacy_lists.default = default_list_name; - end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then - default_list = { name = default_list_name, items = {} }; - privacy_lists.lists[default_list_name] = default_list; - end - local items = default_list.items; - local order = items[1] and items[1].order or 0; -- Must come first - for i=1,#items do -- order must be unique - local item = items[i]; - item.order = item.order + 1; - if item.type == "jid" and item.action == "deny" and item.value == jid then - return false; - end - end - table.insert(items, 1, { type = "jid" - , action = "deny" - , value = jid - , message = false - , ["presence-out"] = false - , ["presence-in"] = false - , iq = false - , order = order - }); - datamanager.store(username, host, "privacy", privacy_lists); - return true; -end - --- Remove JID from default privacy list -function remove_blocked_jid(username, host, jid) - local privacy_lists = datamanager.load(username, host, "privacy") or {}; - local default_list_name = privacy_lists.default; - if not default_list_name then return; end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then return; end - local items = default_list.items; - local item, removed = nil, false; - for i=1,#items do -- order must be unique - item = items[i]; - if item.type == "jid" and item.action == "deny" and item.value == jid then - table.remove(items, i); - removed = true; - break; - end - end - if removed then - datamanager.store(username, host, "privacy", privacy_lists); - end - return removed; -end - -function remove_all_blocked_jids(username, host) - local privacy_lists = datamanager.load(username, host, "privacy") or {}; - local default_list_name = privacy_lists.default; - if not default_list_name then return; end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then return; end - local items = default_list.items; - local item; - for i=#items,1,-1 do -- order must be unique - item = items[i]; - if item.type == "jid" and item.action == "deny" then - table.remove(items, i); - end - end - datamanager.store(username, host, "privacy", privacy_lists); - return true; -end - -function get_blocked_jids(username, host) - -- Return array of blocked JIDs in default privacy list - local privacy_lists = datamanager.load(username, host, "privacy") or {}; - local default_list_name = privacy_lists.default; - if not default_list_name then return {}; end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then return {}; end - local items = default_list.items; - local item; - local jid_list = {}; - for i=1,#items do -- order must be unique - item = items[i]; - if item.type == "jid" and item.action == "deny" then - jid_list[#jid_list+1] = item.value; - end - end - return jid_list; -end - -local function send_push_iqs(username, host, command_type, jids) - local bare_jid = username.."@"..host; - - local stanza_content = st.stanza(command_type, { xmlns = xmlns_blocking }); - for _, jid in ipairs(jids) do - stanza_content:tag("item", { jid = jid }):up(); - end - - for resource, session in pairs(prosody.bare_sessions[bare_jid].sessions) do - local iq_push_stanza = st.iq({ type = "set", to = bare_jid.."/"..resource, id = "blocking-push" }); - iq_push_stanza:add_child(stanza_content); - session.send(iq_push_stanza); - end -end - -function handle_blocking_command(event) - local session, stanza = event.origin, event.stanza; - - local username, host = jid_split(stanza.attr.from); - if stanza.attr.type == "set" then - if stanza.tags[1].name == "block" then - local block = stanza.tags[1]; - local block_jid_list = {}; - for item in block:childtags() do - block_jid_list[#block_jid_list+1] = item.attr.jid; - end - if #block_jid_list == 0 then - session.send(st.error_reply(stanza, "modify", "bad-request")); - else - for _, jid in ipairs(block_jid_list) do - add_blocked_jid(username, host, jid); - end - session.send(st.reply(stanza)); - send_push_iqs(username, host, "block", block_jid_list); - end - return true; - elseif stanza.tags[1].name == "unblock" then - local unblock = stanza.tags[1]; - local unblock_jid_list = {}; - for item in unblock:childtags() do - unblock_jid_list[#unblock_jid_list+1] = item.attr.jid; - end - if #unblock_jid_list == 0 then - remove_all_blocked_jids(username, host); - else - for _, jid_to_unblock in ipairs(unblock_jid_list) do - remove_blocked_jid(username, host, jid_to_unblock); - end - end - session.send(st.reply(stanza)); - send_push_iqs(username, host, "unblock", unblock_jid_list); - return true; - end - elseif stanza.attr.type == "get" and stanza.tags[1].name == "blocklist" then - local reply = st.reply(stanza):tag("blocklist", { xmlns = xmlns_blocking }); - local blocked_jids = get_blocked_jids(username, host); - for _, jid in ipairs(blocked_jids) do - reply:tag("item", { jid = jid }):up(); - end - session.send(reply); - return true; - end -end - -module:hook("iq/self/urn:xmpp:blocking:blocklist", handle_blocking_command); -module:hook("iq/self/urn:xmpp:blocking:block", handle_blocking_command); -module:hook("iq/self/urn:xmpp:blocking:unblock", handle_blocking_command); diff --git a/plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua b/plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua deleted file mode 100644 index 406a0b0..0000000 --- a/plugins/mod_carbons_adhoc/mod_carbons_adhoc.lua +++ /dev/null @@ -1,40 +0,0 @@ --- Implement a Adhoc command which will show a user --- the status of carbons generation in regard to his clients --- --- Copyright (C) 2012 Michael Holzt --- --- This file is MIT/X11 licensed. - -local st = require "util.stanza"; -local jid_bare = require "util.jid".bare; -local adhoc_new = module:require "adhoc".new; -local xmlns_carbons_v2 = "urn:xmpp:carbons:2"; -local xmlns_carbons_v1 = "urn:xmpp:carbons:1"; -local xmlns_carbons_v0 = "urn:xmpp:carbons:0"; - -local bare_sessions = bare_sessions; - -local function adhoc_status(self, data, state) - local bare_jid = jid_bare(data.from); - local user_sessions = bare_sessions[bare_jid]; - - local result = ""; - - user_sessions = user_sessions and user_sessions.sessions; - for _, session in pairs(user_sessions) do - if session.full_jid then - result = result .. session.full_jid .. ": " .. - ( (session.want_carbons == xmlns_carbons_v2 and "v2" ) or - (session.want_carbons == xmlns_carbons_v1 and "v1" ) or - (session.want_carbons == xmlns_carbons_v0 and "v0" ) or - "none" ) .. "\n"; - end - end - - return { info = result, status = "completed" }; -end - -local status_desc = adhoc_new("Carbons: Get Status", - "mod_carbons_adhoc#status", adhoc_status); - -module:add_item("adhoc", status_desc); diff --git a/plugins/mod_carbons_copies/mod_carbons_copies.lua b/plugins/mod_carbons_copies/mod_carbons_copies.lua deleted file mode 100644 index a798263..0000000 --- a/plugins/mod_carbons_copies/mod_carbons_copies.lua +++ /dev/null @@ -1,63 +0,0 @@ --- Send carbons v0 style copies of incoming messages to clients which --- are not (yet) capable of Message Carbons (XEP-0280). --- --- This extension integrates with the mod_carbons plugin in such a way --- that a client capable of Message Carbons will not get a v0 copy. --- --- This extension can be enabled for all users by default by setting --- carbons_copies_default = true. --- --- Alternatively or additionally setting carbons_copies_adhoc = true --- will allow the user to enable or disable copies through Adhoc --- commands. --- --- Copyright (C) 2012 Michael Holzt --- --- This file is MIT/X11 licensed. - -local jid_split = require "util.jid".split; -local dm_load = require "util.datamanager".load; -local dm_store = require "util.datamanager".store; -local adhoc_new = module:require "adhoc".new; -local xmlns_carbons_v0 = "urn:xmpp:carbons:0"; -local storename = "mod_carbons_copies"; - -local function toggle_copies(data, on) - local username, hostname, resource = jid_split(data.from); - dm_store(username, hostname, storename, { enabled = on }); -end - -local function adhoc_enable_copies(self, data, state) - toggle_copies(data, true); - return { info = "Copies are enabled for you now.\nPlease restart/reconnect clients.", status = "completed" }; -end - -local function adhoc_disable_copies(self, data, state) - toggle_copies(data, false); - return { info = "Copies are disabled for you now.\nPlease restart/reconnect clients.", status = "completed" }; -end - -module:hook("resource-bind", function(event) - local session = event.session; - local username, hostname, resource = jid_split(session.full_jid); - - local store = dm_load(username, hostname, storename) or - { enabled = - module:get_option_boolean("carbons_copies_default") }; - - if store.enabled then - session.want_carbons = xmlns_carbons_v0; - module:log("debug", "%s enabling copies", session.full_jid); - end -end); - --- Adhoc-Support -if module:get_option_boolean("carbons_copies_adhoc") then - local enable_desc = adhoc_new("Carbons: Enable Copies", - "mod_carbons_copies#enable", adhoc_enable_copies); - local disable_desc = adhoc_new("Carbons: Disable Copies", - "mod_carbons_copies#disable", adhoc_disable_copies); - - module:add_item("adhoc", enable_desc); - module:add_item("adhoc", disable_desc); -end diff --git a/plugins/mod_filter_chatstates/README.markdown b/plugins/mod_filter_chatstates/README.markdown deleted file mode 100644 index 66d8898..0000000 --- a/plugins/mod_filter_chatstates/README.markdown +++ /dev/null @@ -1,26 +0,0 @@ ---- -summary: Drop chat states from messages to inactive sessions -... - -Introduction -============ - -Some mobile XMPP client developers consider [Chat State -Notifications](http://xmpp.org/extensions/xep-0085.html) to be a waste -of power and bandwidth, especially when the user is not actively looking -at their device. This module will filter them out while the session is -considered inactive. It depends on [mod\_csi](/mod_csi.html) for -deciding when to begin and end filtering. - -Configuration -============= - -There is no configuration for this module, just add it to -modules\_enabled as normal. - -Compatibility -============= - - ----- ------- - 0.9 Works - ----- ------- diff --git a/plugins/mod_filter_chatstates/mod_filter_chatstates.lua b/plugins/mod_filter_chatstates/mod_filter_chatstates.lua deleted file mode 100644 index ea21578..0000000 --- a/plugins/mod_filter_chatstates/mod_filter_chatstates.lua +++ /dev/null @@ -1,31 +0,0 @@ -local filters = require "util.filters"; -local st = require "util.stanza"; - -module:depends("csi"); - -local function chatstate_tag_filter(tag) - if tag.attr.xmlns ~= "http://jabber.org/protocol/chatstates" then - return tag; - end -end - -local function filter_chatstates(stanza) - if stanza.name == "message" then - stanza = st.clone(stanza); - stanza:maptags(chatstate_tag_filter); - if #stanza.tags == 0 then - return nil; - end - end - return stanza; -end - -module:hook("csi-client-inactive", function (event) - local session = event.origin; - filters.add_filter(session, "stanzas/out", filter_chatstates); -end); - -module:hook("csi-client-active", function (event) - local session = event.origin; - filters.remove_filter(session, "stanzas/out", filter_chatstates); -end); diff --git a/plugins/mod_limit_auth/README.markdown b/plugins/mod_limit_auth/README.markdown deleted file mode 100644 index 4cf3143..0000000 --- a/plugins/mod_limit_auth/README.markdown +++ /dev/null @@ -1,35 +0,0 @@ ---- -summary: Throttle authentication attempts with optional tarpit -... - -Introduction -============ - -This module lets you put a per-IP limit on the number of failed -authentication attempts. - -It features an optioanal -[tarpit](https://en.wikipedia.org/wiki/Tarpit_%28networking%29), i.e. -waiting some time before returning an "authentication failed" response. - -Configuration -============= - -``` {.lua} -modules_enabled = { - -- your other modules - "limit_auth"; -} - -limit_auth_period = 30 -- over 30 seconds - -limit_auth_max = 5 -- tolerate no more than 5 failed attempts - - -- Will only work with Prosody trunk: -limit_auth_tarpit_delay = 10 -- delay answer this long -``` - -Compatibility -============= - -Requires 0.9 or later. The tarpit feature requires Prosody trunk. diff --git a/plugins/mod_limit_auth/mod_limit_auth.lua b/plugins/mod_limit_auth/mod_limit_auth.lua deleted file mode 100644 index 5dbc8aa..0000000 --- a/plugins/mod_limit_auth/mod_limit_auth.lua +++ /dev/null @@ -1,58 +0,0 @@ --- mod_limit_auth - -local st = require"util.stanza"; -local new_throttle = require "util.throttle".create; - -local period = math.max(module:get_option_number(module.name.."_period", 30), 0); -local max = math.max(module:get_option_number(module.name.."_max", 5), 1); - -local tarpit_delay = module:get_option_number(module.name.."_tarpit_delay", nil); -if tarpit_delay then - local waiter = require "util.async".waiter; - local delay = tarpit_delay; - function tarpit_delay() - local wait, done = waiter(); - module:add_timer(delay, done); - wait(); - end -else - function tarpit_delay() end -end - -local throttles = module:shared"throttles"; - -local reply = st.stanza("failure", { xmlns = "urn:ietf:params:xml:ns:xmpp-sasl" }):tag("temporary-auth-failure"); - -local function get_throttle(ip) - local throttle = throttles[ip]; - if not throttle then - throttle = new_throttle(max, period); - throttles[ip] = throttle; - end - return throttle; -end - -module:hook("stanza/urn:ietf:params:xml:ns:xmpp-sasl:auth", function (event) - local origin = event.origin; - if origin.type ~= "c2s_unauthed" then return end - if not get_throttle(origin.ip):peek(1) then - origin.log("warn", "Too many authentication attepmts for ip %s", origin.ip); - tarpit_delay(); - origin.send(reply); - return true; - end -end, 10); - -module:hook("authentication-failure", function (event) - get_throttle(event.session.ip):poll(1); -end); - -module:add_timer(14400, function (now) - local old = now - 86400; - for ip, throttle in pairs(throttles) do - if throttle.t < old then - throttles[ip] = nil; - end - end -end); - diff --git a/plugins/mod_log_auth/README.markdown b/plugins/mod_log_auth/README.markdown deleted file mode 100644 index 6e74d01..0000000 --- a/plugins/mod_log_auth/README.markdown +++ /dev/null @@ -1,49 +0,0 @@ ---- -labels: -- 'Stage-Stable' -summary: Log failed authentication attempts with their IP address -... - -Introduction -============ - -Prosody doesn't write IP addresses to its log file by default for -privacy reasons (unless debug logging is enabled). - -This module enables logging of the IP address in a failed authentication -attempt so that those trying to break into accounts for example can be -blocked. - -fail2ban configuration -====================== - -fail2ban is a utility for monitoring log files and automatically -blocking "bad" IP addresses at the firewall level. - -With this module enabled in Prosody you can use the following example -configuration for fail2ban: - - # /etc/fail2ban/filter.d/prosody-auth.conf - # Fail2Ban configuration file for prosody authentication - [Definition] - failregex = Failed authentication attempt \(not-authorized\) for user .* from IP: - ignoreregex = - -And at the appropriate place (usually the bottom) of -/etc/fail2ban/jail.conf add these lines: - - [prosody] - enabled = true - port = 5222 - filter = prosody-auth - logpath = /var/log/prosody/prosody*.log - maxretry = 6 - -Compatibility -------------- - - ------- -------------- - trunk Works - 0.9 Works - 0.8 Doesn't work - ------- -------------- diff --git a/plugins/mod_log_auth/mod_log_auth.lua b/plugins/mod_log_auth/mod_log_auth.lua deleted file mode 100644 index ae32f0e..0000000 --- a/plugins/mod_log_auth/mod_log_auth.lua +++ /dev/null @@ -1,19 +0,0 @@ -local mode = module:get_option_string("log_auth_ips", "failure"); -assert(({ all = true, failure = true, success = true })[mode], - "Unknown log mode: "..tostring(mode).." - valid modes are 'all', 'failure', 'success'"); - -if mode == "failure" or mode == "all" then - module:hook("authentication-failure", function (event) - local session = event.session; - local username = session.username or session.sasl_handler and session.sasl_handler.username or "?"; - session.log("info", "Failed authentication attempt (%s) for user %s@%s from IP: %s", - event.condition or "unknown-condition", username, module.host, session.ip or "?"); - end); -end - -if mode == "success" or mode == "all" then - module:hook("authentication-success", function (event) - local session = event.session; - session.log("info", "Successful authentication as %s@%s from IP: %s", session.username, module.host, session.ip or "?"); - end); -end diff --git a/plugins/mod_shard.lua b/plugins/mod_shard.lua deleted file mode 100644 index 37775b5..0000000 --- a/plugins/mod_shard.lua +++ /dev/null @@ -1,196 +0,0 @@ --- Prosody IM --- Copyright (C) 2015 Robert Norris --- Copyright (C) 2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- -module:depends("sipwise_redis_sessions"); -module:depends("sipwise_redis_mucs"); - -local redis_sessions = module:shared("/*/sipwise_redis_sessions/redis_sessions"); -local redis_mucs = module:shared("/*/sipwise_redis_mucs/redis_mucs"); -local hosts = prosody.hosts; -local jid_split = require "util.jid".split; -local jid_bare = require "util.jid".bare; -local fire_event = prosody.events.fire_event; -local st = require "util.stanza"; -local set = require "util.set"; - -local shard_name = module:get_option("shard_name", nil); -if not shard_name then - error("shard_name not configured", 0); -end -local persistent_rooms = module:open_store("persistent", "map"); -module:log("info", "%s added to shard %s", module.host, shard_name); - -local function build_query_result(rooms, stanza) - local xmlns = 'http://jabber.org/protocol/disco#items'; - local s = stanza:query(xmlns); - for room in rooms do - s:tag("item", {jid=room}):up(); - end - return stanza; -end - -local function get_local_rooms(host) - local rooms = set.new(); - for room in hosts[host].modules.muc.live_rooms() do - rooms:add(room.jid); - end - return rooms; -end - -local function is_local_room(room_jid) - local node, host, _ = jid_split(room_jid); - if not node then return false; end - - if not hosts[host] or not hosts[host].modules.muc then - return false; - end - for room in hosts[host].modules.muc.live_rooms() do - if room.jid == room_jid then return true; end - end - return false; -end - -local function is_persistent_room(jid) - local room_jid = jid_bare(jid); - local res = persistent_rooms:get(nil, room_jid); - module:log("debug", "[%s] is_persistent:%s", room_jid, tostring(res)); - if res then return true else return false end; -end - -local function check_redis_info(room_jid) - local rhost = redis_mucs.get_room_host(room_jid); - - if not rhost then return; end - if rhost ~= shard_name then - module:log("info", "clean wrong shard info for room[%s]", room_jid); - redis_mucs.clean_room_host(room_jid, rhost); - redis_mucs.set_room_host(room_jid, shard_name); - end -end - -local function handle_room_event(event) - local to = event.stanza.attr.to; - local node, host, _ = jid_split(to); - local rhost, room_jid; - - if node then - room_jid = jid_bare(to); - if is_local_room(room_jid) then - module:log("debug", "room[%s] is hosted here. Nothing to do", room_jid); - check_redis_info(room_jid); - return nil; - end - module:log("debug", "looking up target room shard for %s", to); - rhost = redis_mucs.get_room_host(to); - else - -- TODO: remove me this is just for check if there are missing rooms - local rooms = set.union(get_local_rooms(host), - redis_mucs.get_rooms(host)); - module:log("debug", "rooms: %s", tostring(rooms)); - local stanza = build_query_result(rooms, st.reply(event.stanza)); - module:log("debug", "reply[%s]", tostring(stanza)); - event.origin.send(stanza); - return true; - end - - if not rhost then - assert(room_jid); - if is_persistent_room(room_jid) then - module:log("info", - "restore missing info for persistent room[%s]", room_jid); - redis_mucs.set_room_host(room_jid, shard_name); - else - module:log("debug", "room[%s] not found, nothing to do", room_jid); - end - return nil; - end - - if rhost == shard_name then - module:log("debug", "room[%s] is hosted here, nothing to do", room_jid); - return nil - end - - fire_event("shard/send", { shard = rhost, stanza = event.stanza }); - return true; -end - -local function handle_event (event) - local to = event.stanza.attr.to; - local node, host, resource = jid_split(to); - local stop_process_local; - - if not host then - module:log("debug", "no host, nothing to do here"); - return nil - end - - if hosts[host].modules.muc then - module:log("debug", "to MUC %s detected", host); - return handle_room_event(event); - end - - if resource and prosody.full_sessions[to] then - module:log("debug", "%s has a session here, nothing to do", to); - return nil - end - - if not node then - module:log("debug", "no node, nothing to do here"); - return nil - end - - module:log("debug", "looking up target shard for %s", to); - - local rhosts = redis_sessions.get_hosts(to); - for shard,resources in pairs(rhosts) do - if shard and shard ~= shard_name then - for _,r in pairs(resources) do - local stanza_c = st.clone(event.stanza); - stanza_c.attr.to = node..'@'..host..'/'..r; - module:log("debug", "target shard for %s is %s", - stanza_c.attr.to ,shard); - fire_event("shard/send", { shard = shard, stanza = stanza_c }); - stop_process_local = true; - end - end - end - - if prosody.bare_sessions[jid_bare(to)] then - module:log("debug", "%s has a bare session here.".. - " stanza will be processed here too", to); - return nil; - end - - return stop_process_local; -end - -local function handle_shard_error(event) - local server_id = event.shard - local stanza = event.stanza - local jid = stanza.attr.to; - local _, host, _ = jid_split(jid); - - if hosts[host].modules.muc then - module:log("debug", - "to MUC %s detected, clean conference %s", host, jid); - redis_mucs.clean_room_host(jid, server_id) - else - redis_sessions.clean_host(jid, server_id) - end -end - -module:hook("iq/bare", handle_event, 1000); -module:hook("iq/full", handle_event, 1000); -module:hook("iq/host", handle_event, 1000); -module:hook("message/bare", handle_event, 1000); -module:hook("message/full", handle_event, 1000); -module:hook("message/host", handle_event, 1000); -module:hook("presence/bare", handle_event, 1000); -module:hook("presence/full", handle_event, 1000); -module:hook("presence/host", handle_event, 1000); -module:hook_global("shard/error", handle_shard_error); -module:log("debug", "hooked at %s", module:get_host()); diff --git a/plugins/mod_shard_client.lua b/plugins/mod_shard_client.lua deleted file mode 100644 index f124e75..0000000 --- a/plugins/mod_shard_client.lua +++ /dev/null @@ -1,230 +0,0 @@ --- Prosody IM --- Copyright (C) 2015 Robert Norris --- Copyright (C) 2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- -module:set_global(); -local socket = require "socket" -local ut = require "ngcp.utils"; -local logger = require "util.logger"; -local st = require "util.stanza"; -local new_xmpp_stream = require "util.xmppstream".new; -local wrapclient = require "net.server".wrapclient; -local log = module._log; -local shard_name = module:get_option("shard_name", nil); -if not shard_name then - error("shard_name not configured", 0); -end -local opt_keepalives = module:get_option_boolean("shard_tcp_keepalives", module:get_option_boolean("tcp_keepalives", true)); - -local conns = {}; -local queue = {}; - -local listener = {}; - -local sessions = module:shared("sessions"); - -local xmlns_shard = 'prosody:shard'; -local stream_callbacks = { default_ns = xmlns_shard }; - -local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; - -function stream_callbacks.error(session, error, data, _) - if session.destroyed then return; end - module:log("warn", "Error processing shard stream: %s", tostring(error)); - if error == "no-stream" then - session:close("invalid-namespace"); - elseif error == "parse-error" then - session.log("warn", "External shard %s XML parse error: %s", tostring(session.host), tostring(data)); - session:close("not-well-formed"); - elseif error == "stream-error" then - local condition, text = "undefined-condition"; - for child in data:children() do - if child.attr.xmlns == xmlns_xmpp_streams then - if child.name ~= "text" then - condition = child.name; - else - text = child:get_text(); - end - if condition ~= "undefined-condition" and text then - break; - end - end - end - text = condition .. (text and (" ("..text..")") or ""); - session.log("info", "Session closed by remote with error: %s", text); - session:close(nil, text); - end -end - -function stream_callbacks.streamclosed(session) - session.log("debug", "Received "); - session:close(); -end - -local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; -local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" }; -local function session_close(session, reason) - if session.destroyed then return; end - if session.conn then - if session.notopen then - session.send(""); - session.send(st.stanza("stream:stream", default_stream_attr):top_tag()); - end - if reason then - if type(reason) == "string" then -- assume stream error - module:log("info", "Disconnecting component, is: %s", reason); - session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); - elseif type(reason) == "table" then - if reason.condition then - local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up(); - if reason.text then - stanza:tag("text", stream_xmlns_attr):text(reason.text):up(); - end - if reason.extra then - stanza:add_child(reason.extra); - end - module:log("info", "Disconnecting component, is: %s", tostring(stanza)); - session.send(stanza); - elseif reason.name then -- a stanza - module:log("info", "Disconnecting component, is: %s", tostring(reason)); - session.send(reason); - end - end - end - session.send(""); - session.conn:close(); - listener.ondisconnect(session.conn, "stream error"); - end -end - -function listener.onconnect(conn) - local shard = conn:ip(); - - local session = { type = "shard", conn = conn, send = function (data) return conn:write(tostring(data)); end, shard = shard }; - - -- Logging functions -- - local conn_name = "sc"..tostring(session):match("[a-f0-9]+$"); - session.log = logger.init(conn_name); - session.close = session_close; - - if opt_keepalives then - conn:setoption("keepalive", opt_keepalives); - end - - session.log("info", "outgoing shard connection"); - - local stream = new_xmpp_stream(session, stream_callbacks); - session.stream = stream; - - function session.data(_, data) - local ok, err = stream:feed(data); - if ok then return; end - module:log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); - session:close("not-well-formed"); - end - - session.dispatch_stanza = stream_callbacks.handlestanza; - - session.notopen = true; - session.send(st.stanza("stream:stream", { - to = conn:ip(), - ["xmlns:stream"] = 'http://etherx.jabber.org/streams'; - xmlns = xmlns_shard; - }):top_tag()); - - local _queue = queue[shard]; - for _,s in pairs(_queue) do - conn:write(tostring(s)); - end - queue[shard] = nil; - - sessions[conn] = session; -end -function listener.onincoming(conn, data) - local session = sessions[conn]; - session.data(conn, data); -end -function listener.ondisconnect(conn, err) - local session = sessions[conn]; - - if (session) then - (session.log or log)("info", "shard disconnected: %s (%s)", tostring(session.shard), tostring(err)); - if session.on_destroy then session:on_destroy(err); end - sessions[conn] = nil; - conns[session.shard] = nil; - for k in pairs(session) do - if k ~= "log" and k ~= "close" then - session[k] = nil; - end - end - session.destroyed = true; - end - - module:log("error", "connection lost"); - module:fire_event("shard/disconnected", { reason = err, shard = conn:ip() }); -end - -local function connect(shard) - local conn = socket.tcp ( ) - conn:settimeout ( 10 ) - local ok, err = conn:connect (shard, 7473) - if not ok and err ~= "timeout" then - return nil, err; - end - - local handler, _ = wrapclient ( conn , shard , 7473 , listener , "*a") - return handler; -end - -module:hook_global("server-stopping", function(event) - local reason = event.reason; - for _, session in pairs(sessions) do - session:close{ condition = "system-shutdown", text = reason }; - end -end, 1000); - -local function handle_send(event) - local shard = event.shard; - local stanza = event.stanza; - - module:log("debug", "got stanza for shard "..shard) - - local conn = conns[shard]; - if conn == nil then - module:log("debug", "connecting to "..shard.." for delivery"); - local err; - conn, err = connect(shard); - if not conn then - module:log("error", "couldn't connect to "..shard..": "..err); - module:fire_event("shard/error", {shard = shard, stanza = stanza}); - return; - end - conns[shard] = conn; - queue[shard] = {}; - end - if stanza.attr.via then - local via = ut.explode(';', stanza.attr.via); - module:log("debug", "via:%s", ut.table.tostring(via)); - if ut.table.contains(via, shard_name) then - module:log("error", "loop detected, stanza[%s]", stanza); - return; - end - table.insert(via, shard_name); - stanza.attr.via = ut.implode(';', via); - else - stanza.attr.via = shard_name; - end - module:log("debug", "new via:%s", stanza.attr.via); - - local session = sessions[conn] - if session == nil then - table.insert(queue[shard], stanza) - else - conn:write(tostring(stanza)); - end -end - -module:hook_global("shard/send", handle_send, 1000); diff --git a/plugins/mod_shard_server.lua b/plugins/mod_shard_server.lua deleted file mode 100644 index a3e44e1..0000000 --- a/plugins/mod_shard_server.lua +++ /dev/null @@ -1,208 +0,0 @@ --- Prosody IM --- Copyright (C) 2015 Robert Norris --- Copyright (C) 2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -module:set_global(); -local logger = require "util.logger" -local log = logger.init("shard_server"); -local st = require "util.stanza"; -local jid_split = require "util.jid".split; - -local new_xmpp_stream = require "util.xmppstream".new; -local uuid_gen = require "util.uuid".generate; - -local core_process_stanza = prosody.core_process_stanza; -local hosts = prosody.hosts; - -local traceback = debug.traceback; - -local shard_name = module:get_option("shard_name", nil); -if not shard_name then - error("shard_name not configured", 0); -end - -local opt_keepalives = module:get_option_boolean("shard_tcp_keepalives", module:get_option_boolean("tcp_keepalives", true)); - -local sessions = module:shared("sessions"); - ---- Network and stream part --- - -local xmlns_shard = 'prosody:shard'; - -local listener = {}; - ---- Callbacks/data for xmppstream to handle streams for us --- - -local stream_callbacks = { default_ns = xmlns_shard }; - -local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; - -function stream_callbacks.error(session, error, data, _) - if session.destroyed then return; end - module:log("warn", "Error processing component stream: %s", tostring(error)); - if error == "no-stream" then - session:close("invalid-namespace"); - elseif error == "parse-error" then - session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(data)); - session:close("not-well-formed"); - elseif error == "stream-error" then - local condition, text = "undefined-condition"; - for child in data:children() do - if child.attr.xmlns == xmlns_xmpp_streams then - if child.name ~= "text" then - condition = child.name; - else - text = child:get_text(); - end - if condition ~= "undefined-condition" and text then - break; - end - end - end - text = condition .. (text and (" ("..text..")") or ""); - session.log("info", "Session closed by remote with error: %s", text); - session:close(nil, text); - end -end - -function stream_callbacks.streamopened(session, attr) - if attr.to ~= shard_name then - session:close{ condition = "host-unknown", text = "unknown shard name "..tostring(attr.to) }; - return; - end - session.host = attr.to; - session.streamid = uuid_gen(); - session.notopen = nil; -end - -function stream_callbacks.streamclosed(session) - session.log("debug", "Received "); - session:close(); -end - -local function handleerr(err) log("error", "Traceback[component]: %s", traceback(tostring(err), 2)); end -function stream_callbacks.handlestanza(_, stanza) - local to = stanza.attr.to; - local _, host = jid_split(to); - - if not host then return end - - local h = hosts[host]; - local nh = {}; - for k,v in pairs(h) do nh[k] = v; end - nh.type = "component"; - - return xpcall(function () return core_process_stanza(nh, stanza) end, handleerr); -end - ---- Closing a component connection -local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; -local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" }; -local function session_close(session, reason) - if session.destroyed then return; end - if session.conn then - if session.notopen then - session.send(""); - session.send(st.stanza("stream:stream", default_stream_attr):top_tag()); - end - if reason then - if type(reason) == "string" then -- assume stream error - module:log("info", "Disconnecting component, is: %s", reason); - session.send(st.stanza("stream:error"):tag(reason, {xmlns = 'urn:ietf:params:xml:ns:xmpp-streams' })); - elseif type(reason) == "table" then - if reason.condition then - local stanza = st.stanza("stream:error"):tag(reason.condition, stream_xmlns_attr):up(); - if reason.text then - stanza:tag("text", stream_xmlns_attr):text(reason.text):up(); - end - if reason.extra then - stanza:add_child(reason.extra); - end - module:log("info", "Disconnecting component, is: %s", tostring(stanza)); - session.send(stanza); - elseif reason.name then -- a stanza - module:log("info", "Disconnecting component, is: %s", tostring(reason)); - session.send(reason); - end - end - end - session.send(""); - session.conn:close(); - listener.ondisconnect(session.conn, "stream error"); - end -end - ---- Component connlistener - -function listener.onconnect(conn) - local _send = conn.write; - local session = { type = "shard", conn = conn, send = function (data) return _send(conn, tostring(data)); end }; - - -- Logging functions -- - local conn_name = "ss"..tostring(session):match("[a-f0-9]+$"); - session.log = logger.init(conn_name); - session.close = session_close; - - if opt_keepalives then - conn:setoption("keepalive", opt_keepalives); - end - - session.log("info", "incoming shard connection"); - - local stream = new_xmpp_stream(session, stream_callbacks); - session.stream = stream; - - session.notopen = true; - - function session.reset_stream() - session.notopen = true; - session.stream:reset(); - end - - function session.data(_, data) - local ok, err = stream:feed(data); - if ok then return; end - module:log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); - session:close("not-well-formed"); - end - - session.dispatch_stanza = stream_callbacks.handlestanza; - - sessions[conn] = session; -end -function listener.onincoming(conn, data) - local session = sessions[conn]; - session.data(conn, data); -end -function listener.ondisconnect(conn, err) - local session = sessions[conn]; - if session then - (session.log or log)("info", "component disconnected: %s (%s)", tostring(session.host), tostring(err)); - if session.on_destroy then session:on_destroy(err); end - sessions[conn] = nil; - for k in pairs(session) do - if k ~= "log" and k ~= "close" then - session[k] = nil; - end - end - session.destroyed = true; - end -end - -function listener.ondetach(conn) - sessions[conn] = nil; -end - -module:provides("net", { - name = "shard"; - private = true; - listener = listener; - default_port = 7473; - multiplex = { - pattern = "^<.*:stream.*%sxmlns%s*=%s*(['\"])"..xmlns_shard.."%1.*>"; - }; -}); diff --git a/plugins/mod_sipwise_admin_telnet.lua b/plugins/mod_sipwise_admin_telnet.lua deleted file mode 100644 index 359d236..0000000 --- a/plugins/mod_sipwise_admin_telnet.lua +++ /dev/null @@ -1,1123 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- Copyright (C) 2013 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -module:set_global(); - -local hostmanager = require "core.hostmanager"; -local modulemanager = require "core.modulemanager"; -local s2smanager = require "core.s2smanager"; -local portmanager = require "core.portmanager"; - -local _G = _G; - -local prosody = _G.prosody; -local hosts = prosody.hosts; -local incoming_s2s = prosody.incoming_s2s; - -local console_listener = { - default_port = module:get_option_number("console_port", 5582); - default_mode = "*a"; - interface = module:get_option_string("console_interface", "127.0.0.1"); -}; - -local iterators = require "util.iterators"; -local keys, values = iterators.keys, iterators.values; -local jid_bare, jid_split = import("util.jid", "bare", "prepped_split"); -local set, array = require "util.set", require "util.array"; -local cert_verify_identity = require "util.x509".verify_identity; -local envload = require "util.envload".envload; -local envloadfile = require "util.envload".envloadfile; - -local commands = module:shared("commands") -local def_env = module:shared("env"); -local default_env_mt = { __index = def_env }; -local core_post_stanza = prosody.core_post_stanza; - -local function redirect_output(_G, session) - local env = setmetatable({ print = session.print }, { __index = function (t, k) return rawget(_G, k); end }); - env.dofile = function(name) - local f, err = envloadfile(name, env); - if not f then return f, err; end - return f(); - end; - return env; -end - -console = {}; - -function console:new_session(conn) - local w = function(s) conn:write(s:gsub("\n", "\r\n")); end; - local session = { conn = conn; - send = function (t) w(tostring(t)); end; - print = function (...) - local t = {}; - for i=1,select("#", ...) do - t[i] = tostring(select(i, ...)); - end - w("| "..table.concat(t, "\t").."\n"); - end; - disconnect = function () conn:close(); end; - }; - session.env = setmetatable({}, default_env_mt); - - -- Load up environment with helper objects - for name, t in pairs(def_env) do - if type(t) == "table" then - session.env[name] = setmetatable({ session = session }, { __index = t }); - end - end - - return session; -end - -function console:process_line(session, line) - local useglobalenv; - - if line:match("^>") then - line = line:gsub("^>", ""); - useglobalenv = true; - elseif line == "\004" then - commands["bye"](session, line); - return; - else - local command = line:match("^%w+") or line:match("%p"); - if commands[command] then - commands[command](session, line); - return; - end - end - - session.env._ = line; - - local chunkname = "=console"; - local env = (useglobalenv and redirect_output(_G, session)) or session.env or nil - local chunk, err = envload("return "..line, chunkname, env); - if not chunk then - chunk, err = envload(line, chunkname, env); - if not chunk then - err = err:gsub("^%[string .-%]:%d+: ", ""); - err = err:gsub("^:%d+: ", ""); - err = err:gsub("''", "the end of the line"); - session.print("Sorry, I couldn't understand that... "..err); - return; - end - end - - local ranok, taskok, message = pcall(chunk); - - if not (ranok or message or useglobalenv) and commands[line:lower()] then - commands[line:lower()](session, line); - return; - end - - if not ranok then - session.print("Fatal error while running command, it did not complete"); - session.print("Error: "..taskok); - return; - end - - if not message then - session.print("Result: "..tostring(taskok)); - return; - elseif (not taskok) and message then - session.print("Command completed with a problem"); - session.print("Message: "..tostring(message)); - return; - end - - session.print("OK: "..tostring(message)); -end - -local sessions = {}; - -function console_listener.onconnect(conn) - -- Handle new connection - local session = console:new_session(conn); - sessions[conn] = session; - printbanner(session); - session.send(string.char(0)); -end - -function console_listener.onincoming(conn, data) - local session = sessions[conn]; - - local partial = session.partial_data; - if partial then - data = partial..data; - end - - for line in data:gmatch("[^\n]*[\n\004]") do - if session.closed then return end - console:process_line(session, line); - session.send(string.char(0)); - end - session.partial_data = data:match("[^\n]+$"); -end - -function console_listener.ondisconnect(conn, err) - local session = sessions[conn]; - if session then - session.disconnect(); - sessions[conn] = nil; - end -end - -function console_listener.ondetach(conn) - sessions[conn] = nil; -end - --- Console commands -- --- These are simple commands, not valid standalone in Lua - -function commands.bye(session) - session.print("See you! :)"); - session.closed = true; - session.disconnect(); -end -commands.quit, commands.exit = commands.bye, commands.bye; - -commands["!"] = function (session, data) - if data:match("^!!") and session.env._ then - session.print("!> "..session.env._); - return console_listener.onincoming(session.conn, session.env._); - end - local old, new = data:match("^!(.-[^\\])!(.-)!$"); - if old and new then - local ok, res = pcall(string.gsub, session.env._, old, new); - if not ok then - session.print(res) - return; - end - session.print("!> "..res); - return console_listener.onincoming(session.conn, res); - end - session.print("Sorry, not sure what you want"); -end - - -function commands.help(session, data) - local print = session.print; - local section = data:match("^help (%w+)"); - if not section then - print [[Commands are divided into multiple sections. For help on a particular section, ]] - print [[type: help SECTION (for example, 'help c2s'). Sections are: ]] - print [[]] - print [[c2s - Commands to manage local client-to-server sessions]] - print [[s2s - Commands to manage sessions between this server and others]] - print [[module - Commands to load/reload/unload modules/plugins]] - print [[host - Commands to activate, deactivate and list virtual hosts]] - print [[user - Commands to create and delete users, and change their passwords]] - print [[server - Uptime, version, shutting down, etc.]] - print [[port - Commands to manage ports the server is listening on]] - print [[dns - Commands to manage and inspect the internal DNS resolver]] - print [[config - Reloading the configuration, etc.]] - print [[console - Help regarding the console itself]] - elseif section == "c2s" then - print [[c2s:show(jid) - Show all client sessions with the specified JID (or all if no JID given)]] - print [[c2s:show_insecure() - Show all unencrypted client connections]] - print [[c2s:show_secure() - Show all encrypted client connections]] - print [[c2s:close(jid) - Close all sessions for the specified JID]] - elseif section == "s2s" then - print [[s2s:show(domain) - Show all s2s connections for the given domain (or all if no domain given)]] - print [[s2s:close(from, to) - Close a connection from one domain to another]] - print [[s2s:closeall(host) - Close all the incoming/outgoing s2s sessions to specified host]] - elseif section == "module" then - print [[module:load(module, host) - Load the specified module on the specified host (or all hosts if none given)]] - print [[module:reload(module, host) - The same, but unloads and loads the module (saving state if the module supports it)]] - print [[module:unload(module, host) - The same, but just unloads the module from memory]] - print [[module:list(host) - List the modules loaded on the specified host]] - elseif section == "host" then - print [[host:activate(hostname) - Activates the specified host]] - print [[host:deactivate(hostname) - Disconnects all clients on this host and deactivates]] - print [[host:list() - List the currently-activated hosts]] - elseif section == "user" then - print [[user:create(jid, password) - Create the specified user account]] - print [[user:password(jid, password) - Set the password for the specified user account]] - print [[user:delete(jid) - Permanently remove the specified user account]] - print [[user:list(hostname, pattern) - List users on the specified host, optionally filtering with a pattern]] - elseif section == "server" then - print [[server:version() - Show the server's version number]] - print [[server:uptime() - Show how long the server has been running]] - print [[server:memory() - Show details about the server's memory usage]] - print [[server:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]] - elseif section == "port" then - print [[port:list() - Lists all network ports prosody currently listens on]] - print [[port:close(port, interface) - Close a port]] - elseif section == "dns" then - print [[dns:lookup(name, type, class) - Do a DNS lookup]] - print [[dns:addnameserver(nameserver) - Add a nameserver to the list]] - print [[dns:setnameserver(nameserver) - Replace the list of name servers with the supplied one]] - print [[dns:purge() - Clear the DNS cache]] - print [[dns:cache() - Show cached records]] - elseif section == "config" then - print [[config:reload() - Reload the server configuration. Modules may need to be reloaded for changes to take effect.]] - elseif section == "console" then - print [[Hey! Welcome to Prosody's admin console.]] - print [[First thing, if you're ever wondering how to get out, simply type 'quit'.]] - print [[Secondly, note that we don't support the full telnet protocol yet (it's coming)]] - print [[so you may have trouble using the arrow keys, etc. depending on your system.]] - print [[]] - print [[For now we offer a couple of handy shortcuts:]] - print [[!! - Repeat the last command]] - print [[!old!new! - repeat the last command, but with 'old' replaced by 'new']] - print [[]] - print [[For those well-versed in Prosody's internals, or taking instruction from those who are,]] - print [[you can prefix a command with > to escape the console sandbox, and access everything in]] - print [[the running server. Great fun, but be careful not to break anything :)]] - end - print [[]] -end - --- Session environment -- --- Anything in def_env will be accessible within the session as a global variable - -def_env.server = {}; - -function def_env.server:insane_reload() - prosody.unlock_globals(); - dofile "prosody" - prosody = _G.prosody; - return true, "Server reloaded"; -end - -function def_env.server:version() - return true, tostring(prosody.version or "unknown"); -end - -function def_env.server:uptime() - local t = os.time()-prosody.start_time; - local seconds = t%60; - t = (t - seconds)/60; - local minutes = t%60; - t = (t - minutes)/60; - local hours = t%24; - t = (t - hours)/24; - local days = t; - return true, string.format("This server has been running for %d day%s, %d hour%s and %d minute%s (since %s)", - days, (days ~= 1 and "s") or "", hours, (hours ~= 1 and "s") or "", - minutes, (minutes ~= 1 and "s") or "", os.date("%c", prosody.start_time)); -end - -function def_env.server:shutdown(reason) - prosody.shutdown(reason); - return true, "Shutdown initiated"; -end - -local function human(kb) - local unit = "K"; - if kb > 1024 then - kb, unit = kb/1024, "M"; - end - return ("%0.2f%sB"):format(kb, unit); -end - -function def_env.server:memory() - local pposix = require("util.pposix"); - if not pposix.meminfo then - return true, "Lua is using "..collectgarbage("count"); - end - local mem, lua_mem = pposix.meminfo(), collectgarbage("count"); - local print = self.session.print; - print("Process: "..human((mem.allocated+mem.allocated_mmap)/1024)); - print(" Used: "..human(mem.used/1024).." ("..human(lua_mem).." by Lua)"); - print(" Free: "..human(mem.unused/1024).." ("..human(mem.returnable/1024).." returnable)"); - return true, "OK"; -end - -def_env.module = {}; - -local function get_hosts_set(hosts, module) - if type(hosts) == "table" then - if hosts[1] then - return set.new(hosts); - elseif hosts._items then - return hosts; - end - elseif type(hosts) == "string" then - return set.new { hosts }; - elseif hosts == nil then - local mm = require "modulemanager"; - local hosts_set = set.new(array.collect(keys(prosody.hosts))) - / function (host) return (prosody.hosts[host].type == "local" or module and mm.is_loaded(host, module)) and host or nil; end; - if module and mm.get_module("*", module) then - hosts_set:add("*"); - end - return hosts_set; - end -end - -function def_env.module:load(name, hosts, config) - local mm = require "modulemanager"; - - hosts = get_hosts_set(hosts); - - -- Load the module for each host - local ok, err, count, mod = true, nil, 0, nil; - for host in hosts do - if (not mm.is_loaded(host, name)) then - mod, err = mm.load(host, name, config); - if not mod then - ok = false; - if err == "global-module-already-loaded" then - if count > 0 then - ok, err, count = true, nil, 1; - end - break; - end - self.session.print(err or "Unknown error loading module"); - else - count = count + 1; - self.session.print("Loaded for "..mod.module.host); - end - end - end - - return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); -end - -function def_env.module:unload(name, hosts) - local mm = require "modulemanager"; - - hosts = get_hosts_set(hosts, name); - - -- Unload the module for each host - local ok, err, count = true, nil, 0; - for host in hosts do - if mm.is_loaded(host, name) then - ok, err = mm.unload(host, name); - if not ok then - ok = false; - self.session.print(err or "Unknown error unloading module"); - else - count = count + 1; - self.session.print("Unloaded from "..host); - end - end - end - return ok, (ok and "Module unloaded from "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); -end - -function def_env.module:reload(name, hosts) - local mm = require "modulemanager"; - - hosts = array.collect(get_hosts_set(hosts, name)):sort(function (a, b) - if a == "*" then return true - elseif b == "*" then return false - else return a < b; end - end); - - -- Reload the module for each host - local ok, err, count = true, nil, 0; - for _, host in ipairs(hosts) do - if mm.is_loaded(host, name) then - ok, err = mm.reload(host, name); - if not ok then - ok = false; - self.session.print(err or "Unknown error reloading module"); - else - count = count + 1; - if ok == nil then - ok = true; - end - self.session.print("Reloaded on "..host); - end - end - end - return ok, (ok and "Module reloaded on "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); -end - -function def_env.module:list(hosts) - if hosts == nil then - hosts = array.collect(keys(prosody.hosts)); - table.insert(hosts, 1, "*"); - end - if type(hosts) == "string" then - hosts = { hosts }; - end - if type(hosts) ~= "table" then - return false, "Please supply a host or a list of hosts you would like to see"; - end - - local print = self.session.print; - for _, host in ipairs(hosts) do - print((host == "*" and "Global" or host)..":"); - local modules = array.collect(keys(modulemanager.get_modules(host) or {})):sort(); - if #modules == 0 then - if prosody.hosts[host] then - print(" No modules loaded"); - else - print(" Host not found"); - end - else - for _, name in ipairs(modules) do - print(" "..name); - end - end - end -end - -def_env.config = {}; -function def_env.config:load(filename, format) - local config_load = require "core.configmanager".load; - local ok, err = config_load(filename, format); - if not ok then - return false, err or "Unknown error loading config"; - end - return true, "Config loaded"; -end - -function def_env.config:get(host, section, key) - local config_get = require "core.configmanager".get - return true, tostring(config_get(host, section, key)); -end - -function def_env.config:reload() - local ok, err = prosody.reload_config(); - return ok, (ok and "Config reloaded (you may need to reload modules to take effect)") or tostring(err); -end - -def_env.hosts = {}; -function def_env.hosts:list() - for host, host_session in pairs(hosts) do - self.session.print(host); - end - return true, "Done"; -end - -function def_env.hosts:add(name) -end - -def_env.c2s = {}; - -local function show_c2s(callback) - for hostname, host in pairs(hosts) do - for username, user in pairs(host.sessions or {}) do - for resource, session in pairs(user.sessions or {}) do - local jid = username.."@"..hostname.."/"..resource; - callback(jid, session); - end - end - end -end - -function def_env.c2s:count(match_jid) - local count = 0; - show_c2s(function (jid, session) - if (not match_jid) or jid:match(match_jid) then - count = count + 1; - end - end); - return true, "Total: "..count.." clients"; -end - -function def_env.c2s:show(match_jid) - local print, count = self.session.print, 0; - local curr_host; - show_c2s(function (jid, session) - if curr_host ~= session.host then - curr_host = session.host; - print(curr_host); - end - if (not match_jid) or jid:match(match_jid) then - count = count + 1; - local status, priority = "unavailable", tostring(session.priority or "-"); - if session.presence then - status = session.presence:child_with_name("show"); - if status then - status = status:get_text() or "[invalid!]"; - else - status = "available"; - end - end - print(" "..jid.." - "..status.."("..priority..")"); - end - end); - return true, "Total: "..count.." clients"; -end - -function def_env.c2s:show_insecure(match_jid) - local print, count = self.session.print, 0; - show_c2s(function (jid, session) - if ((not match_jid) or jid:match(match_jid)) and not session.secure then - count = count + 1; - print(jid); - end - end); - return true, "Total: "..count.." insecure client connections"; -end - -function def_env.c2s:show_secure(match_jid) - local print, count = self.session.print, 0; - show_c2s(function (jid, session) - if ((not match_jid) or jid:match(match_jid)) and session.secure then - count = count + 1; - print(jid); - end - end); - return true, "Total: "..count.." secure client connections"; -end - -function def_env.c2s:close(match_jid) - local count = 0; - show_c2s(function (jid, session) - if jid == match_jid or jid_bare(jid) == match_jid then - count = count + 1; - session:close(); - end - end); - return true, "Total: "..count.." sessions closed"; -end - -local function session_flags(session, line) - if session.cert_identity_status == "valid" then - line[#line+1] = "(secure)"; - elseif session.secure then - line[#line+1] = "(encrypted)"; - end - if session.compressed then - line[#line+1] = "(compressed)"; - end - if session.smacks then - line[#line+1] = "(sm)"; - end - if session.conn and session.conn:ip():match(":") then - line[#line+1] = "(IPv6)"; - end - return table.concat(line, " "); -end - -def_env.s2s = {}; -function def_env.s2s:show(match_jid) - local _print = self.session.print; - local print = self.session.print; - - local count_in, count_out = 0,0; - - for host, host_session in pairs(hosts) do - print = function (...) _print(host); _print(...); print = _print; end - for remotehost, session in pairs(host_session.s2sout) do - if (not match_jid) or remotehost:match(match_jid) or host:match(match_jid) then - count_out = count_out + 1; - print(session_flags(session, {" ", host, "->", remotehost})); - if session.sendq then - print(" There are "..#session.sendq.." queued outgoing stanzas for this connection"); - end - if session.type == "s2sout_unauthed" then - if session.connecting then - print(" Connection not yet established"); - if not session.srv_hosts then - if not session.conn then - print(" We do not yet have a DNS answer for this host's SRV records"); - else - print(" This host has no SRV records, using A record instead"); - end - elseif session.srv_choice then - print(" We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts); - local srv_choice = session.srv_hosts[session.srv_choice]; - print(" Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269)); - end - elseif session.notopen then - print(" The has not yet been opened"); - elseif not session.dialback_key then - print(" Dialback has not been initiated yet"); - elseif session.dialback_key then - print(" Dialback has been requested, but no result received"); - end - end - end - end - local subhost_filter = function (h) - return (match_jid and h:match(match_jid)); - end - for session in pairs(incoming_s2s) do - if session.to_host == host and ((not match_jid) or host:match(match_jid) - or (session.from_host and session.from_host:match(match_jid)) - -- Pft! is what I say to list comprehensions - or (session.hosts and #array.collect(keys(session.hosts)):filter(subhost_filter)>0)) then - count_in = count_in + 1; - print(session_flags(session, {" ", host, "<-", session.from_host or "(unknown)"})); - if session.type == "s2sin_unauthed" then - print(" Connection not yet authenticated"); - end - for name in pairs(session.hosts) do - if name ~= session.from_host then - print(" also hosts "..tostring(name)); - end - end - end - end - - print = _print; - end - - for session in pairs(incoming_s2s) do - if not session.to_host and ((not match_jid) or session.from_host and session.from_host:match(match_jid)) then - count_in = count_in + 1; - print("Other incoming s2s connections"); - print(" (unknown) <- "..(session.from_host or "(unknown)")); - end - end - - return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections"; -end - -local function print_subject(print, subject) - for _, entry in ipairs(subject) do - print( - (" %s: %q"):format( - entry.name or entry.oid, - entry.value:gsub("[\r\n%z%c]", " ") - ) - ); - end -end - --- As much as it pains me to use the 0-based depths that OpenSSL does, --- I think there's going to be more confusion among operators if we --- break from that. -local function print_errors(print, errors) - for depth, t in pairs(errors) do - print( - (" %d: %s"):format( - depth-1, - table.concat(t, "\n| ") - ) - ); - end -end - -function def_env.s2s:showcert(domain) - local ser = require "util.serialization".serialize; - local print = self.session.print; - local domain_sessions = set.new(array.collect(keys(incoming_s2s))) - /function(session) return session.from_host == domain and session or nil; end; - for local_host in values(prosody.hosts) do - local s2sout = local_host.s2sout; - if s2sout and s2sout[domain] then - domain_sessions:add(s2sout[domain]); - end - end - local cert_set = {}; - for session in domain_sessions do - local conn = session.conn; - conn = conn and conn:socket(); - if not conn.getpeerchain then - if conn.dohandshake then - error("This version of LuaSec does not support certificate viewing"); - end - else - local cert = conn:getpeercertificate(); - if cert then - local certs = conn:getpeerchain(); - local digest = cert:digest("sha1"); - if not cert_set[digest] then - local chain_valid, chain_errors = conn:getpeerverification(); - cert_set[digest] = { - { - from = session.from_host, - to = session.to_host, - direction = session.direction - }; - chain_valid = chain_valid; - chain_errors = chain_errors; - certs = certs; - }; - else - table.insert(cert_set[digest], { - from = session.from_host, - to = session.to_host, - direction = session.direction - }); - end - end - end - end - local domain_certs = array.collect(values(cert_set)); - -- Phew. We now have a array of unique certificates presented by domain. - local n_certs = #domain_certs; - - if n_certs == 0 then - return "No certificates found for "..domain; - end - - local function _capitalize_and_colon(byte) - return string.upper(byte)..":"; - end - local function pretty_fingerprint(hash) - return hash:gsub("..", _capitalize_and_colon):sub(1, -2); - end - - for cert_info in values(domain_certs) do - local certs = cert_info.certs; - local cert = certs[1]; - print("---") - print("Fingerprint (SHA1): "..pretty_fingerprint(cert:digest("sha1"))); - print(""); - local n_streams = #cert_info; - print("Currently used on "..n_streams.." stream"..(n_streams==1 and "" or "s")..":"); - for _, stream in ipairs(cert_info) do - if stream.direction == "incoming" then - print(" "..stream.to.." <- "..stream.from); - else - print(" "..stream.from.." -> "..stream.to); - end - end - print(""); - local chain_valid, errors = cert_info.chain_valid, cert_info.chain_errors; - local valid_identity = cert_verify_identity(domain, "xmpp-server", cert); - if chain_valid then - print("Trusted certificate: Yes"); - else - print("Trusted certificate: No"); - print_errors(print, errors); - end - print(""); - print("Issuer: "); - print_subject(print, cert:issuer()); - print(""); - print("Valid for "..domain..": "..(valid_identity and "Yes" or "No")); - print("Subject:"); - print_subject(print, cert:subject()); - end - print("---"); - return ("Showing "..n_certs.." certificate" - ..(n_certs==1 and "" or "s") - .." presented by "..domain.."."); -end - -function def_env.s2s:close(from, to) - local print, count = self.session.print, 0; - - if not (from and to) then - return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'"; - elseif from == to then - return false, "Both from and to are the same... you can't do that :)"; - end - - if hosts[from] and not hosts[to] then - -- Is an outgoing connection - local session = hosts[from].s2sout[to]; - if not session then - print("No outgoing connection from "..from.." to "..to) - else - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - print("Closed outgoing session from "..from.." to "..to); - end - elseif hosts[to] and not hosts[from] then - -- Is an incoming connection - for session in pairs(incoming_s2s) do - if session.to_host == to and session.from_host == from then - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - end - end - - if count == 0 then - print("No incoming connections from "..from.." to "..to); - else - print("Closed "..count.." incoming session"..((count == 1 and "") or "s").." from "..from.." to "..to); - end - elseif hosts[to] and hosts[from] then - return false, "Both of the hostnames you specified are local, there are no s2s sessions to close"; - else - return false, "Neither of the hostnames you specified are being used on this server"; - end - - return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); -end - -function def_env.s2s:closeall(host) - local count = 0; - - if not host or type(host) ~= "string" then return false, "wrong syntax: please use s2s:closeall('hostname.tld')"; end - if hosts[host] then - for session in pairs(incoming_s2s) do - if session.to_host == host then - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - end - end - for _, session in pairs(hosts[host].s2sout) do - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - end - else - for session in pairs(incoming_s2s) do - if session.from_host == host then - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - end - end - for _, h in pairs(hosts) do - if h.s2sout[host] then - (h.s2sout[host].close or s2smanager.destroy_session)(h.s2sout[host]); - count = count + 1; - end - end - end - - if count == 0 then return false, "No sessions to close."; - else return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end -end - -def_env.host = {}; def_env.hosts = def_env.host; - -function def_env.host:activate(hostname, config) - return hostmanager.activate(hostname, config); -end -function def_env.host:deactivate(hostname, reason) - return hostmanager.deactivate(hostname, reason); -end - -function def_env.host:list() - local print = self.session.print; - local i = 0; - for host in values(array.collect(keys(prosody.hosts)):sort()) do - i = i + 1; - print(host); - end - return true, i.." hosts"; -end - -def_env.port = {}; - -function def_env.port:list() - local print = self.session.print; - local services = portmanager.get_active_services().data; - local ordered_services, n_ports = {}, 0; - for service, interfaces in pairs(services) do - table.insert(ordered_services, service); - end - table.sort(ordered_services); - for _, service in ipairs(ordered_services) do - local ports_list = {}; - for interface, ports in pairs(services[service]) do - for port in pairs(ports) do - table.insert(ports_list, "["..interface.."]:"..port); - end - end - n_ports = n_ports + #ports_list; - print(service..": "..table.concat(ports_list, ", ")); - end - return true, #ordered_services.." services listening on "..n_ports.." ports"; -end - -function def_env.port:close(close_port, close_interface) - close_port = assert(tonumber(close_port), "Invalid port number"); - local n_closed = 0; - local services = portmanager.get_active_services().data; - for service, interfaces in pairs(services) do - for interface, ports in pairs(interfaces) do - if not close_interface or close_interface == interface then - if ports[close_port] then - self.session.print("Closing ["..interface.."]:"..close_port.."..."); - local ok, err = portmanager.close(interface, close_port) - if not ok then - self.session.print("Failed to close "..interface.." "..close_port..": "..err); - else - n_closed = n_closed + 1; - end - end - end - end - end - return true, "Closed "..n_closed.." ports"; -end - -def_env.muc = {}; - -local console_room_mt = { - __index = function (self, k) return self.room[k]; end; - __tostring = function (self) - return "MUC room <"..self.room.jid..">"; - end; -}; - -local function check_muc(jid) - local room_name, host = jid_split(jid); - if not hosts[host] then - return nil, "No such host: "..host; - elseif not hosts[host].modules.muc then - return nil, "Host '"..host.."' is not a MUC service"; - end - return room_name, host; -end - -function def_env.muc:create(room_jid) - local room, host = check_muc(room_jid); - if not room_name then - return room_name, host; - end - if not room then return nil, host end - if hosts[host].modules.muc.rooms[room_jid] then return nil, "Room exists already" end - return hosts[host].modules.muc.create_room(room_jid); -end - -function def_env.muc:room(room_jid) - local room_name, host = check_muc(room_jid); - if not room_name then - return room_name, host; - end - local room_obj = hosts[host].modules.muc.rooms[room_jid]; - if not room_obj then - return nil, "No such room: "..room_jid; - end - return setmetatable({ room = room_obj }, console_room_mt); -end - -local um = require"core.usermanager"; - -def_env.user = {}; -function def_env.user:create(jid, password) - local username, host = jid_split(jid); - if not hosts[host] then - return nil, "No such host: "..host; - elseif um.user_exists(username, host) then - return nil, "User exists"; - end - local ok, err = um.create_user(username, password, host); - if ok then - return true, "User created"; - else - return nil, "Could not create user: "..err; - end -end - -function def_env.user:delete(jid) - local username, host = jid_split(jid); - if not hosts[host] then - return nil, "No such host: "..host; - elseif not um.user_exists(username, host) then - return nil, "No such user"; - end - local ok, err = um.delete_user(username, host); - if ok then - return true, "User deleted"; - else - return nil, "Could not delete user: "..err; - end -end - -function def_env.user:password(jid, password) - local username, host = jid_split(jid); - if not hosts[host] then - return nil, "No such host: "..host; - elseif not um.user_exists(username, host) then - return nil, "No such user"; - end - local ok, err = um.set_password(username, password, host); - if ok then - return true, "User password changed"; - else - return nil, "Could not change password for user: "..err; - end -end - -function def_env.user:list(host, pat) - if not host then - return nil, "No host given"; - elseif not hosts[host] then - return nil, "No such host"; - end - local print = self.session.print; - local total, matches = 0, 0; - for user in um.users(host) do - if not pat or user:match(pat) then - print(user.."@"..host); - matches = matches + 1; - end - total = total + 1; - end - return true, "Showing "..(pat and (matches.." of ") or "all " )..total.." users"; -end - -def_env.xmpp = {}; - -local st = require "util.stanza"; -function def_env.xmpp:ping(localhost, remotehost) - if hosts[localhost] then - core_post_stanza(hosts[localhost], - st.iq{ from=localhost, to=remotehost, type="get", id="ping" } - :tag("ping", {xmlns="urn:xmpp:ping"})); - return true, "Sent ping"; - else - return nil, "No such host"; - end -end - -def_env.dns = {}; -local adns = require"net.adns"; -local dns = require"net.dns"; - -function def_env.dns:lookup(name, typ, class) - local ret = "Query sent"; - local print = self.session.print; - local function handler(...) - ret = "Got response"; - print(...); - end - adns.lookup(handler, name, typ, class); - return true, ret; -end - -function def_env.dns:addnameserver(...) - dns._resolver:addnameserver(...) - return true -end - -function def_env.dns:setnameserver(...) - dns._resolver:setnameserver(...) - return true -end - -function def_env.dns:purge() - dns.purge() - return true -end - -function def_env.dns:cache() - return true, "Cache:\n"..tostring(dns.cache()) -end - -------------- - -function printbanner(session) - local option = module:get_option("console_banner"); - if option == nil or option == "full" or option == "graphic" then - session.print [[ - ____ \ / _ - | _ \ _ __ ___ ___ _-_ __| |_ _ - | |_) | '__/ _ \/ __|/ _ \ / _` | | | | - | __/| | | (_) \__ \ |_| | (_| | |_| | - |_| |_| \___/|___/\___/ \__,_|\__, | - A study in simplicity |___/ - -]] - end - if option == nil or option == "short" or option == "full" then - session.print("Welcome to the Prosody administration console. For a list of commands, type: help"); - session.print("You may find more help on using this console in our online documentation at "); - session.print("http://prosody.im/doc/console\n"); - end - if option and option ~= "short" and option ~= "full" and option ~= "graphic" then - if type(option) == "string" then - session.print(option) - elseif type(option) == "function" then - module:log("warn", "Using functions as value for the console_banner option is no longer supported"); - end - end -end - -module:provides("net", { - name = "console"; - listener = console_listener; - default_port = 5582; - private = true; -}); diff --git a/plugins/mod_sipwise_groups.lua b/plugins/mod_sipwise_groups.lua deleted file mode 100644 index c4dde23..0000000 --- a/plugins/mod_sipwise_groups.lua +++ /dev/null @@ -1,287 +0,0 @@ --- Load PBX groups from DDBB --- Copyright (C) 2013 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -local lookup_query = [[ -SELECT g.username, s.username, d.domain -FROM provisioning.voip_subscribers AS s -LEFT JOIN provisioning.voip_domains AS d ON s.domain_id = d.id -LEFT JOIN provisioning.voip_pbx_groups AS ug ON s.id = ug.subscriber_id -LEFT JOIN provisioning.voip_subscribers AS g ON g.id = ug.group_id -LEFT JOIN provisioning.voip_usr_preferences as p ON p.subscriber_id = s.id -WHERE s.account_id = ? AND s.is_pbx_group = 0 AND s.is_pbx_pilot = 0 -AND ug.group_id IS NOT NULL -AND (p.attribute_id = ? AND p.value = '1') -ORDER BY s.username; -]]; - -local lookup_with_dn_query = [[ -SELECT s.username, d.domain, p.value -FROM provisioning.voip_subscribers AS s -LEFT JOIN provisioning.voip_domains AS d ON s.domain_id = d.id -LEFT JOIN provisioning.voip_usr_preferences as p ON p.subscriber_id = s.id -LEFT JOIN provisioning.voip_pbx_groups AS ug ON s.id = ug.subscriber_id -WHERE s.account_id = ? AND s.is_pbx_group = 0 AND s.is_pbx_pilot = 0 -AND ug.group_id IS NOT NULL -AND p.attribute_id = ? -ORDER BY s.username; -]]; - -local lookup_user_group_query = [[ -SELECT g.username -FROM provisioning.voip_subscribers AS s -LEFT JOIN provisioning.voip_domains AS d ON s.domain_id = d.id -LEFT JOIN provisioning.voip_pbx_groups AS ug ON s.id = ug.subscriber_id -LEFT JOIN provisioning.voip_subscribers AS g ON g.id = ug.group_id -WHERE s.account_id = ? AND -s.username = ? AND d.domain = ? AND -s.is_pbx_group = 0 AND s.is_pbx_pilot = 0 AND ug.group_id IS NOT NULL; -]]; - -local lookup_users_by_groups_query = [[ -SELECT g.username, s.username, d.domain -FROM provisioning.voip_subscribers AS s -LEFT JOIN provisioning.voip_domains AS d ON s.domain_id = d.id -LEFT JOIN provisioning.voip_pbx_groups AS ug ON s.id = ug.subscriber_id -LEFT JOIN provisioning.voip_subscribers AS g ON g.id = ug.group_id -LEFT JOIN provisioning.voip_usr_preferences as p ON p.subscriber_id = s.id -WHERE s.account_id = ? AND s.is_pbx_group = 0 AND s.is_pbx_pilot = 0 -AND ug.group_id IS NOT NULL -AND (p.attribute_id = ? AND p.value = '1') AND g.username in (?) -ORDER BY s.username; -]]; - -local lookup_all_query = [[ -SELECT s.username, d.domain -FROM provisioning.voip_subscribers AS s -LEFT JOIN provisioning.voip_domains AS d ON s.domain_id = d.id -LEFT JOIN provisioning.voip_usr_preferences as p ON p.subscriber_id = s.id -WHERE s.account_id = ? AND s.is_pbx_group = 0 AND s.is_pbx_pilot = 0 -AND (p.attribute_id = ? AND p.value = '1') -ORDER BY s.username; -]]; - -local account_id_query = [[ -SELECT account_id -FROM provisioning.voip_subscribers -WHERE username = ? AND -domain_id = ( SELECT id FROM provisioning.voip_domains where domain = ?); -]] - -local lookupt_preference_id_query = [[ -SELECT id -FROM provisioning.voip_preferences -WHERE attribute = ?; -]] - --- from table to string --- t = {'a','b'} --- implode(",",t,"'") --- "'a','b'" --- implode("#",t) --- "a#b" -local function implode(delimiter, list, quoter) - local len = #list - if not delimiter then - error("delimiter is nil") - end - if len == 0 then - return nil - end - if not quoter then - quoter = "" - end - local string = quoter .. list[1] .. quoter - for i = 2, len do - string = string .. delimiter .. quoter .. list[i] .. quoter - end - return string -end - -local sql = require "util.sql"; -local default_params = module:get_option("sql"); -local engine; - --- Reconnect to DB if necessary -local function reconect_check() - if not engine.conn:ping() then - engine.conn = nil; - module:log("debug", "DDBB reconecting"); - engine:connect(); - engine:execute("SET NAMES 'utf8' COLLATE 'utf8_bin';"); - end -end - --- returns the attribute_id of 'shared_buddylist_visiblility' preference -local function lookup_buddy_id() - reconect_check(); - local res = engine:select(lookupt_preference_id_query, - 'shared_buddylist_visibility'); - for row in res do -- luacheck: ignore 512 - return row[1] - end - module:log("error", "no 'shared_buddylist_visiblility' preference found!"); -end -local buddylist_preference_id; - --- returns the attribute_id of 'display_name' preference -local function lookup_displayname_id() - reconect_check(); - local res = engine:select(lookupt_preference_id_query, - 'display_name'); - for row in res do -- luacheck: ignore 512 - return row[1] - end - module:log("error", "no 'display_name' preference found!"); -end -local displayname_preference_id; - - --- "roster-load" callback -local function inject_roster_contacts(event) - local username, host, roster = event.username, event.host, event.roster; - module:log("debug", "Injecting group members to roster"); - local bare_jid = username.."@"..host; - local account_id, groups, display_names; - - -- returns the account_id of username@host subscriber - local function lookup_account_id() - --module:log("debug", "lookup user '%s@%s'", username, host); - reconect_check(); - for row in engine:select(account_id_query, username, host) do -- luacheck: ignore 512 - module:log("debug", "user '%s@%s' belongs to %d", - username, host, row[1]); - return row[1]; - end - module:log("debug", "no account_id found!"); - end - - -- returns a table with the pbx groups the subscriber - -- belongs to - local function lookup_user_groups() - local result = {}; - reconect_check(); - local res = engine:select(lookup_user_group_query, account_id, - username, host, buddylist_preference_id); - for row in res do - module:log("debug", "found group:'%s'", row[1]); - table.insert(result, row[1]); - end - return result; - end - - -- returns a table with the subscribers display_name - -- key is username@domain - local function lookup_users_dn() - local result = {}; - reconect_check(); - local res = engine:select(lookup_with_dn_query, account_id, - displayname_preference_id); - for row in res do - result[row[1].."@"..row[2]] = row[3]; - end - return result; - end - - -- returns a dictionary with all the subscribers of the account - -- key is the name of the pbx group - -- if all is true a 'all' group will be added with all subscribers - -- if all_groups is false only the groups that bare_jid belongs will be added - local function lookup_groups(all, all_groups) - local res; - local result = {}; - if account_id then - reconect_check(); - - if all_groups then - module:log("debug", "lookup_groups for account_id:%s", - account_id); - res = engine:select(lookup_query, account_id, - buddylist_preference_id); - else - module:log("debug", "lookup_groups for account_id:%s jid:%s@%s", - account_id, username, host); - local user_groups = lookup_user_groups(); - res = engine:select(lookup_users_by_groups_query, - account_id, buddylist_preference_id, - implode(",",user_groups)); - end - for row in res do - if not result[row[1]] then - result[row[1]] = {}; - end - table.insert(result[row[1]], row[2].."@"..row[3]); - end - if all then - result['all'] = {}; - for row in engine:select(lookup_all_query, - account_id, buddylist_preference_id) do - table.insert(result['all'], row[1].."@"..row[2]); - end - end - end - return result; - end - - account_id = lookup_account_id(); - -- TODO: set this parameters from usr_preferences - groups = lookup_groups(true, true); - display_names = lookup_users_dn(); - - local function import_jids_to_roster(group_name) - for _,jid in pairs(groups[group_name]) do - -- Add them to roster - module:log("debug", "processing jid %s in group %s", - tostring(jid), tostring(group_name)); - if jid ~= bare_jid then - if not roster[jid] then roster[jid] = {}; end - roster[jid].subscription = "both"; - -- If we have the subscriber display name - if display_names[jid] then - roster[jid].name = display_names[jid]; - end - if not roster[jid].groups then - roster[jid].groups = { [group_name] = true }; - end - roster[jid].groups[group_name] = true; - roster[jid].persist = false; - end - end - end - - for group_name in pairs(groups) do - module:log("debug", "Importing group %s", group_name); - import_jids_to_roster(group_name); - end - - if roster[false] then - roster[false].version = true; - end -end - -local function normalize_params(params) - assert(params.driver and params.database, - "Configuration error: Both the SQL driver and the database need to be specified"); - return params; -end - -function module.load() - if prosody.prosodyctl then return; end - local engines = module:shared("/*/sql/connections"); - local params = normalize_params(module:get_option("auth_sql", default_params)); - engine = engines[sql.db2uri(params)]; - if not engine then - module:log("debug", "Creating new engine"); - engine = sql:create_engine(params); - engines[sql.db2uri(params)] = engine; - end - engine:connect(); - buddylist_preference_id = lookup_buddy_id(); - displayname_preference_id = lookup_displayname_id(); - - module:hook("roster-load", inject_roster_contacts); - module:log("debug", "Groups loaded successfully"); -end diff --git a/plugins/mod_sipwise_lastactivity.lua b/plugins/mod_sipwise_lastactivity.lua deleted file mode 100644 index 0e4c938..0000000 --- a/plugins/mod_sipwise_lastactivity.lua +++ /dev/null @@ -1,59 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- Copyright (C) 2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - --- TODO: permanent storage -local st = require "util.stanza"; -local is_contact_subscribed = require "core.rostermanager".is_contact_subscribed; -local jid_bare = require "util.jid".bare; -local jid_split = require "util.jid".split; -local sessions = module:shared("sessions"); - -module:add_feature("jabber:iq:last"); - -local map = {}; - --- lastactivity: any change of presence -module:hook("pre-presence/bare", function(event) - local stanza = event.stanza; - if not(stanza.attr.to) then - local t = os.time(); - local s = stanza:get_child_text("status"); - map[event.origin.username] = {s = s, t = t}; - module:log("debug", string.format("change of presence:%s from:%s", - tostring(s), tostring(event.origin.username))); - end -end, 10); - -module:hook("iq-get/bare/jabber:iq:last:query", function(event) - local origin, stanza = event.origin, event.stanza; - local username = jid_split(stanza.attr.to) or origin.username; - if not stanza.attr.to or is_contact_subscribed(username, module.host, jid_bare(stanza.attr.from)) then - local seconds, text = nil, ""; - if not sessions[origin.conn] and map[username] then - seconds = tostring(os.difftime(os.time(), map[username].t)); - text = map[username].s; - end - origin.send(st.reply(stanza):tag('query', {xmlns='jabber:iq:last', seconds=seconds}):text(text)); - else - origin.send(st.error_reply(stanza, 'auth', 'forbidden')); - end - return true; -end); - -local function msg_handler(event) - local origin, stanza = event.origin, event.stanza; - local username = jid_split(stanza.attr.from) or origin.username; - map[username] = {s = "online", t = os.time()}; - module:log("debug", string.format("%s from: %s", - tostring(stanza.attr.type), tostring(username))); -end - --- lastactivity: any message sent -module:hook("pre-message/bare", msg_handler); -module:hook("pre-message/full", msg_handler); diff --git a/plugins/mod_sipwise_log_debug.lua b/plugins/mod_sipwise_log_debug.lua deleted file mode 100644 index 25d009f..0000000 --- a/plugins/mod_sipwise_log_debug.lua +++ /dev/null @@ -1,78 +0,0 @@ --- Copyright (C) 2015 Sipwise GmbH --- --- enable log stanzas/[in|out] by jid --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- -module:set_global(); -local jid = require "util.jid"; -local add_filter = require "util.filters".add_filter; -local ut = require "ngcp.utils"; -local log = module._log; - -local config_default = { - level = "debug", -- log level - prefix_out = "Sent", - prefix_in = "Received", - jids = {}, -- jids to log - filter = {'*'} -- 'message', 'iq' -}; -local config - -local function filter_stanza(stanza) - if ut.table.contains(config.filter, '*') then - return true - end - for _,v in pairs(config.filter) do - if stanza.name == v then - return true - end - if stanza:get_child(v) then - return true - end - end - return false -end - -local function log_stanza(stanza, session, prefix) - if filter_stanza(stanza) then - session.log(config.level, "%s[%s]: %s", prefix, session.full_jid, - tostring(stanza)) - return stanza - end - return stanza -end - -local function log_in_stanza (stanza, session) - return log_stanza(stanza, session, - config.prefix_in or config_default.prefix_in) -end - -local function log_out_stanza (stanza, session) - return log_stanza(stanza, session, - config.prefix_out or config_default.prefix_out) -end - - -local function resource_bind(event) - local session = event.session; - local node, domain, _ = jid.split(session.full_jid); - local bare_jid = node.."@"..domain; - - if ut.table.contains(config.jids, bare_jid) then - add_filter(session, "stanzas/out", log_out_stanza, 1000); - add_filter(session, "stanzas/in", log_in_stanza, 1000); - module:log("info", "log_debug activated for %s for filter %s", - session.full_jid, ut.table.tostring(config.filter)) - end -end - -function module.load() - config = module:get_option("log_debug", config_default); - log("info", "jids: %s", ut.table.tostring(config.jids)) -end - -function module.add_host(module) - module:hook("resource-bind", resource_bind, 200); -end diff --git a/plugins/mod_sipwise_pushd.lua b/plugins/mod_sipwise_pushd.lua deleted file mode 100644 index f1081b9..0000000 --- a/plugins/mod_sipwise_pushd.lua +++ /dev/null @@ -1,564 +0,0 @@ --- --- Copyright (C) 2014-2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -module:depends("sipwise_vcard_cusax"); -module:depends("sipwise_pushd_blocking"); - -local datamanager = require "util.datamanager"; -local sql = require "util.sql"; -local format = string.format; -local jid_split = require "util.jid".split; -local jid_bare = require "util.jid".bare; -local jid_host = require "util.jid".host; -local jid_resource = require "util.jid".resource; -local hosts = prosody.hosts; -local http = require "net.http"; -local uuid = require "util.uuid"; -local ut = require "ngcp.utils"; -local set = require "util.set"; -local st = require "util.stanza"; - -local sipwise_offline = module:shared("sipwise_offline/sipwise_offline"); -local pushd_blocking = module:shared("sipwise_pushd_blocking/pushd_blocking"); - -local muc_config = { - force_persistent = true, - owner_on_join = true, - exclude = {} -}; -local pushd_config = { - url = "https://127.0.0.1:8080/push", - fcm = true, - apns = true, - call_sound = 'incoming_call.caf', - msg_sound = 'incoming_message.caf', - muc_config = muc_config -}; - -local push_usr_query = [[ -SELECT vp.attribute, vup.value FROM provisioning.voip_preferences vp - LEFT JOIN provisioning.voip_usr_preferences vup ON vup.attribute_id = vp.id - LEFT JOIN provisioning.voip_subscribers vs ON vs.id = vup.subscriber_id - LEFT JOIN provisioning.voip_domains vd ON vd.id = vs.domain_id -WHERE vp.attribute = 'mobile_push_enable' - AND vs.username = ? - AND vd.domain = ?; -]]; - -local push_dom_query = [[ -SELECT vp.attribute, vup.value FROM provisioning.voip_preferences vp - LEFT JOIN provisioning.voip_dom_preferences vup ON vup.attribute_id = vp.id - LEFT JOIN provisioning.voip_domains vd ON vd.id = vup.domain_id -WHERE vp.attribute = 'mobile_push_enable' - AND vd.domain = ?; -]]; - -local push_silent_query = [[ -SELECT vp.id FROM provisioning.voip_preferences vp - LEFT JOIN provisioning.voip_usr_preferences vup ON vup.attribute_id = vp.id - LEFT JOIN provisioning.voip_subscribers vs ON vs.id = vup.subscriber_id - LEFT JOIN provisioning.voip_domains vd ON vd.id = vs.domain_id -WHERE vp.attribute = 'mobile_push_silent_list' - AND vs.username = ? - AND vd.domain = ? - AND vup.value = ?; -]]; - -local default_params = module:get_option("sql"); -local engine; - --- Reconnect to DB if necessary -local function reconect_check() - if not engine.conn:ping() then - engine.conn = nil; - engine:connect(); - end -end - --- luacheck: ignore request -local function process_response(response, code, request) - if code >= 200 and code < 299 then - module:log("debug", "pushd response OK[%s] %s", - tostring(code), tostring(response)); - else - module:log("error", "pushd response KO[%s] %s", - tostring(code), tostring(response)); - end -end - -local function push_silent(username, domain, other) - reconect_check(); - for row in engine:select(push_silent_query, username, domain, other) do - module:log("debug", "silent push preference mobile_push_silent_list matches"); - return true; - end - return false; -end - -local function push_enable(username, domain) - reconect_check(); - local flag - - for row in engine:select(push_usr_query, username, domain) do - if row[2] == "never" then - module:log("debug", "usr mobile_push_enable pref set to 'never'"); - return false; - end - module:log("debug", "usr pref %s", ut.table.tostring(row)) - flag = true - end - if flag then return true end - for row in engine:select(push_dom_query, domain) do - if row[2] == "never" then - module:log("debug", "domain mobile_push_enable pref set to 'never'"); - return false; - end - module:log("debug", "dom pref %s", ut.table.tostring(row)) - end - return true; -end - -local function is_local_domain(dom) - return ut.table.contains(ut.table.keys(hosts), dom); -end - -local function get_caller_info(jid, caller_defaults) - if not jid then - return nil; - end - local node, host = jid_split(jid); - if not is_local_domain(host) then - module:log("debug", "caller[%s] not local", jid); - return nil; - end - local vcard = module:shared(format("/%s/sipwise_vcard_cusax/vcard", host)); - if vcard and vcard.get_subscriber_info then - local info = vcard.get_subscriber_info(node, host); - module:log("debug", "caller_info of %s", jid); - if not info.display_name then - module:log("debug", "set display_name to %s", node); - info.display_name = node; - end - if not info.aliases then - info.aliases = caller_defaults.aliases; - end - return info; - end -end - -local function get_members(muc_room) - local res = set.new(); - if muc_room then - for o_jid, _, _ in muc_room:each_affiliation() do - res:add(o_jid); - end - end - return res; -end - -local function get_occupants(muc_room) - local res = set.new(); - for _, occupant in muc_room:each_occupant() do - res:add(jid_bare(occupant.jid)); - end - return res; -end - -local function get_muc_room(room_jid) - local host = jid_host(room_jid); - - if not hosts[host] then - module:log("warn", "host [%s] not defined", tostring(host)); - return nil - end - if not hosts[host].modules.muc then - module:log("warn", "muc not enabled here [%s]", tostring(host)); - return nil - end - return hosts[host].modules.muc.get_room_from_jid(jid_bare(room_jid)); -end - -local function get_muc_caller(room_jid) - local nick = jid_resource(room_jid); - - local room = get_muc_room(room_jid); - if not room then - module:log("warn", "room %s not here", jid_bare(room_jid)); - return nil; - end - return room:get_occupant_by_nick(nick); -end - -local function get_callee_badge(jid) - local node, host = jid_split(jid); - local result = 0; - if sipwise_offline.get_num then - result = sipwise_offline.get_num(node, host); - else - local offline = datamanager.list_load(node, host, "offline"); - if offline then - result = #offline; - end - end - -- plus the one in process - result = result + 1; - module:log("debug", "%d offline messages for %s", result, jid); - return result; -end - -local function is_invite(stanza) - if stanza:get_child('x', 'http://jabber.org/protocol/muc#user') then - return true - end -end - -local function is_attachment(stanza) - if stanza:get_child('x', 'jabber:x:oob') then - return true - end -end - -local function get_message(stanza) - local body = stanza:get_child('body'); - if body then - return body:get_text(); - end -end - -local function get_muc_info(stanza, caller_info) - local from = stanza.attr.from; - local muc_stanza = stanza:get_child('x', 'jabber:x:conference'); - local muc = {}; - local room; - - if muc_stanza then - muc.jid = muc_stanza.attr.jid; - else - muc.jid = jid_bare(from); - end - muc.name, muc.domain = jid_split(muc.jid); - if not is_local_domain(muc.domain) then - module:log("debug", "not from local host[%s]", tostring(muc.domain)); - return nil; - end - local room_host = hosts[muc.domain].modules.muc; - if not room_host then - module:log("debug", "not from MUC host[%s]", muc.domain); - return nil; - end - room = room_host.get_room_from_jid(muc.jid); - if room then - muc.room = room:get_description() or muc.name; - if muc_stanza then - muc.invite = format("Group chat invitation to '%s' from %s", - muc.room, caller_info.display_name); - end - return muc; - end -end - -local function is_pushd_blocked(from, to) - local node_to, host_to = jid_split(to); - local blocked_list = pushd_blocking.get_blocked_jids(node_to, host_to); - - module:log("debug", "pushd_blockedlist: %s for [%s]", ut.table.tostring(blocked_list), to); - - local _, host_from, resource_from = jid_split(from); - if ut.table.contains(blocked_list, from) - or ut.table.contains(blocked_list, jid_bare(from)) - or ut.table.contains(blocked_list, host_from) then - return true; - end - if resource_from and ut.table.contains(blocked_list, host_from.."/"..resource_from) then - return true; - end - return false; -end - -local function handle_offline(event) - module:log("debug", "handle_offline"); - local origin, stanza = event.origin, event.stanza; - local to = stanza.attr.to; - local from = stanza.attr.from; - local node, host; - local caller = { username = 'unknow', host = 'unknown.local' }; - local caller_defaults = {display_name = '', aliases = {''}}; - local caller_info; - -- defaults to "application/x-www-form-urlencoded" - local http_options = { - method = "POST", - body = "", - } - local message; - - local function build_push_common_query(msg, muc) - if muc then - msg.data_room_jid = muc['jid']; - msg.data_room_description = muc['room']; - if msg.data_type == 'invite' then - msg.data_message = muc['invite']; - end - end - msg.data_sender_number = tostring(caller_info.aliases[1]); - msg.data_sender_name = tostring(caller_info.display_name); - return msg; - end - local function build_push_apns_query(msg, muc, silent) - if silent then - msg['apns_content-available'] = '1'; - else - if msg.data_type ~= 'invite' then - msg.apns_alert = string.format("Message from %s:\n", - caller_info.display_name) .. msg.data_message; - else - msg.apns_alert = muc['invite']; - end - msg.apns_sound = pushd_config.msg_sound or ''; - msg.apns_badge = tostring(get_callee_badge(to)); - end - return msg; - end - local function build_push_query(msg) - local muc; - local caller_jid; - local silent; - if stanza.attr.type == 'groupchat' then - msg.data_type = 'groupchat' - caller_jid = get_muc_caller(stanza.attr.from); - module:log("debug", "from:%s -> caller_jid:%s", - tostring(stanza.attr.from), tostring(caller_jid)); - caller_info = get_caller_info(caller_jid, caller_defaults) or - caller_defaults; - muc = get_muc_info(stanza, caller_info); - silent = push_silent(msg.callee, msg.domain, muc['jid']); - else - msg.data_type = 'message'; - caller_jid = format("%s@%s", - origin.username or caller.username, - origin.host or caller.host); - if is_invite(stanza) then - msg.data_type = 'invite'; - caller_jid = jid_bare(stanza:get_child('invite').attr.from) or - caller_jid; - elseif is_attachment(stanza) then - msg.data_message = "new attachment"; - end - caller_info = get_caller_info(caller_jid, caller_defaults) or - caller_defaults; - muc = get_muc_info(stanza, caller_info); - silent = push_silent(msg.callee, msg.domain, caller_jid); - end - if silent then - msg.data_silent = '1'; - else - msg.data_silent = '0'; - end - msg.data_sender_jid = caller_jid; - msg.data_sender_sip = jid_bare(caller_jid); - msg.push_id = uuid.generate(); - msg = build_push_common_query(msg, muc); - if pushd_config.apns then - msg = build_push_apns_query(msg, muc, silent); - end - return msg; - end - - module:log("debug", "stanza[%s]", tostring(stanza)); - - if from then - caller.username, caller.host = jid_split(from); - end - - if to then - node, host = jid_split(to); - if from and is_pushd_blocked(from, to) then - module:log("debug", "skip pushd message from blocked jid [%s]", from); - return nil; - end - message = { - data_message = get_message(stanza), - data_full_message = tostring(stanza), - callee = node, - domain = host, - }; - if message.data_message then - module:log("debug", "message OK"); - if push_enable(node, host) then - message = build_push_query(message); - module:log("debug", "message: %s", ut.table.tostring(message)); - http_options.body = http.formencode(message); - if http_options.body then - module:log("debug", "Sending http pushd request: %s data: %s", - pushd_config.url, http_options.body); - http.request(pushd_config.url, http_options, process_response); - end - else - module:log("debug", "no mobile_push_enable pref set for %s", to); - end - else - module:log("debug", "no message body"); - end - end -end - -local function fire_offline_message(event, muc_room, off_jid) - local stanza_c = st.clone(event.stanza); - local orig_from = event.stanza.attr.from; - stanza_c.attr.to = off_jid; - stanza_c.attr.from = muc_room:get_occupant_jid(orig_from); - - module:log("debug", "stanza[%s] stanza_c[%s]", - tostring(event.stanza), tostring(stanza_c)); - if not stanza_c.attr.from then - module:log("error", "original from[%s] not found at muc_room", - tostring(orig_from)); - return nil; - end - if is_pushd_blocked(stanza_c.attr.from, stanza_c.attr.to) then - module:log("debug", "skip pushd message from blocked jid [%s]", - stanza_c.attr.from); - elseif is_pushd_blocked(orig_from, stanza_c.attr.to) then - module:log("debug", "skip pushd message from blocked jid [%s]", - orig_from); - else - module:fire_event('message/offline/handle', { - origin = event.origin, - stanza = stanza_c, - }); - end -end - -local function handle_muc_offline(event, room_jid) - local _, host = jid_split(room_jid); - local muc = hosts[host].modules.muc; - - if muc then - local muc_room = muc.get_room_from_jid(room_jid); - if not muc_room then - module:log("debug", "muc room[%s] not here. Nothing to do", - room_jid); - return nil; - elseif ut.table.contains(pushd_config.muc_config.exclude, room_jid) then - module:log("debug", "muc room[%s] excluded from pushd", room_jid); - return nil; - end - - local muc_members = get_members(muc_room); - local muc_occ_online = get_occupants(muc_room); - local muc_occ_offline = set.difference(muc_members,muc_occ_online); - module:log("debug", "muc_members[%s]", tostring(muc_members)); - module:log("debug", "muc_occ_online[%s]", tostring(muc_occ_online)); - module:log("debug", "muc_occ_offline[%s]", tostring(muc_occ_offline)); - for off_jid in muc_occ_offline do - module:log("debug", "fire_offline_message[%s]", off_jid); - fire_offline_message(event, muc_room, off_jid); - end - end -end - -local function handle_msg(event) - module:log("debug", "handle_msg"); - local stanza = event.stanza; - local room_jid = stanza.attr.to; - - if stanza.attr.type ~= 'groupchat' then - module:log("debug", - "message[%s] not of type groupchat. Nothing to do here", - tostring(stanza)); - return nil; - end - module:log("debug", "handle_msg room_jid[%s]", tostring(room_jid)); - return handle_muc_offline(event, room_jid); -end - -local function handle_muc_created(event) - local room = event.room; - if pushd_config.muc_config.force_persistent then - room:set_persistent(true); - module:log("debug", "persistent room[%s] forced on creation", - room:get_name()); - end -end - -local function handle_muc_config(event) - local room, fields = event.room, event.fields; - local name = fields['muc#roomconfig_roomname'] or room:get_name(); - local persistent = fields['muc#roomconfig_persistentroom']; - if pushd_config.muc_config.force_persistent and not persistent then - fields['muc#roomconfig_persistentroom'] = true; - event.changed = true; - module:log("debug", "persistent room[%s] forced", name); - end -end - -local function handle_muc_presence(event) - if not pushd_config.muc_config.owner_on_join then return; end - local stanza = event.stanza; - if stanza.attr.type == "unavailable" then return; end - - local room = get_muc_room(stanza.attr.to); - if not room then return; end - local from_jid = jid_bare(stanza.attr.from); - local affiliation = room:get_affiliation(from_jid); - if affiliation ~= "owner" then - room:set_affiliation(true, from_jid, "owner"); - module:log("debug", "[%s] set affiliation to 'owner' for [%s]", - room:get_name(), from_jid); - end -end - -local function handle_muc_presence_out(event) - local stanza = event.stanza; - local muc_stanza = stanza:get_child('x', - 'http://jabber.org/protocol/muc#user'); - - if muc_stanza then - local item = muc_stanza:get_child('item'); - if not item.nick and stanza.attr.from then - local nick = select(3, jid_split(stanza.attr.from)); - if nick then - item.attr.nick = nick; - module:log("debug", "added nick[%s] tag", nick); - end - end - end -end - -if module:get_host_type() == "component" then - module:hook("muc-room-created", handle_muc_created, 20); - module:hook("muc-config-submitted", handle_muc_config, 20); - module:hook("presence/full", handle_muc_presence, 501); -else - module:hook("presence/full", handle_muc_presence_out, 501); -end -module:hook("message/bare", handle_msg, 20); -module:hook("message/offline/handle", handle_offline, 20); - -local function normalize_params(params) - assert(params.driver and params.database, - "Configuration error: Both the SQL driver and the database need to be specified"); - return params; -end - -function module.load() - if prosody.prosodyctl then return; end - local engines = module:shared("/*/sql/connections"); - local params = normalize_params(module:get_option("auth_sql", default_params)); - engine = engines[sql.db2uri(params)]; - if not engine then - module:log("debug", "Creating new engine"); - engine = sql:create_engine(params); - engines[sql.db2uri(params)] = engine; - end - engine:connect(); - pushd_config = module:get_option("pushd_config", pushd_config); - if not pushd_config.muc_config then - pushd_config.muc_config = muc_config - end - - module:log("debug", "load OK"); -end diff --git a/plugins/mod_sipwise_pushd_blocking.lua b/plugins/mod_sipwise_pushd_blocking.lua deleted file mode 100644 index fbfb4fd..0000000 --- a/plugins/mod_sipwise_pushd_blocking.lua +++ /dev/null @@ -1,175 +0,0 @@ -local jid_split = require "util.jid".split; -local st = require "util.stanza"; -local datamanager = require"util.datamanager"; - -local xmlns_blocking = "urn:xmpp:pushd_blocking"; -local datastore = "pushd_privacy"; - -module:add_feature("urn:xmpp:pushd_blocking"); -local pushd_blocking = module:shared("pushd_blocking"); - --- Add JID to default privacy list -local function add_blocked_jid(username, host, jid) - local privacy_lists = datamanager.load(username, host, datastore) or {lists = {}}; - local default_list_name = privacy_lists.default; - if not privacy_lists.lists then - privacy_lists.lists = {} - end - if not default_list_name then - default_list_name = "blocklist"; - privacy_lists.default = default_list_name; - end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then - default_list = { name = default_list_name, items = {} }; - privacy_lists.lists[default_list_name] = default_list; - end - local items = default_list.items; - local order = items[1] and items[1].order or 0; -- Must come first - for i=1,#items do -- order must be unique - local item = items[i]; - item.order = item.order + 1; - if item.type == "jid" and item.action == "deny" and item.value == jid then - return false; - end - end - table.insert(items, 1, { type = "jid" - , action = "deny" - , value = jid - , message = false - , ["presence-out"] = false - , ["presence-in"] = false - , iq = false - , order = order - }); - datamanager.store(username, host, datastore, privacy_lists); - return true; -end - --- Remove JID from default privacy list -local function remove_blocked_jid(username, host, jid) - local privacy_lists = datamanager.load(username, host, datastore) or {}; - local default_list_name = privacy_lists.default; - if not default_list_name then return; end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then return; end - local items = default_list.items; - local item, removed = nil, false; - for i=1,#items do -- order must be unique - item = items[i]; - if item.type == "jid" and item.action == "deny" and item.value == jid then - table.remove(items, i); - removed = true; - break; - end - end - if removed then - datamanager.store(username, host, datastore, privacy_lists); - end - return removed; -end - -local function remove_all_blocked_jids(username, host) - local privacy_lists = datamanager.load(username, host, datastore) or {}; - local default_list_name = privacy_lists.default; - if not default_list_name then return; end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then return; end - local items = default_list.items; - local item; - for i=#items,1,-1 do -- order must be unique - item = items[i]; - if item.type == "jid" and item.action == "deny" then - table.remove(items, i); - end - end - datamanager.store(username, host, datastore, privacy_lists); - return true; -end - -function pushd_blocking.get_blocked_jids(username, host) - -- Return array of blocked JIDs in default privacy list - local privacy_lists = datamanager.load(username, host, datastore) or {}; - local default_list_name = privacy_lists.default; - if not default_list_name then return {}; end - local default_list = privacy_lists.lists[default_list_name]; - if not default_list then return {}; end - local items = default_list.items; - local item; - local jid_list = {}; - for i=1,#items do -- order must be unique - item = items[i]; - if item.type == "jid" and item.action == "deny" then - jid_list[#jid_list+1] = item.value; - end - end - return jid_list; -end - -local function send_push_iqs(username, host, command_type, jids) - local bare_jid = username.."@"..host; - - local stanza_content = st.stanza(command_type, { xmlns = xmlns_blocking }); - for _, jid in ipairs(jids) do - stanza_content:tag("item", { jid = jid }):up(); - end - - for resource, session in pairs(prosody.bare_sessions[bare_jid].sessions) do - local iq_push_stanza = st.iq({ type = "set", to = bare_jid.."/"..resource }); - iq_push_stanza:add_child(stanza_content); - session.send(iq_push_stanza); - end -end - -local function handle_blocking_command(event) - local session, stanza = event.origin, event.stanza; - - local username, host = jid_split(stanza.attr.from); - if stanza.attr.type == "set" then - if stanza.tags[1].name == "block" then - local block = stanza.tags[1]; - local block_jid_list = {}; - for item in block:childtags() do - block_jid_list[#block_jid_list+1] = item.attr.jid; - end - if #block_jid_list == 0 then - session.send(st.error_reply(stanza, "modify", "bad-request")); - else - for _, jid in ipairs(block_jid_list) do - add_blocked_jid(username, host, jid); - end - session.send(st.reply(stanza)); - send_push_iqs(username, host, "block", block_jid_list); - end - return true; - elseif stanza.tags[1].name == "unblock" then - local unblock = stanza.tags[1]; - local unblock_jid_list = {}; - for item in unblock:childtags() do - unblock_jid_list[#unblock_jid_list+1] = item.attr.jid; - end - if #unblock_jid_list == 0 then - remove_all_blocked_jids(username, host); - else - for _, jid_to_unblock in ipairs(unblock_jid_list) do - remove_blocked_jid(username, host, jid_to_unblock); - end - end - session.send(st.reply(stanza)); - send_push_iqs(username, host, "unblock", unblock_jid_list); - return true; - end - elseif stanza.attr.type == "get" and stanza.tags[1].name == "blocklist" then - local reply = st.reply(stanza):tag("blocklist", { xmlns = xmlns_blocking }); - local blocked_jids = pushd_blocking.get_blocked_jids(username, host); - for _, jid in ipairs(blocked_jids) do - reply:tag("item", { jid = jid }):up(); - end - session.send(reply); - return true; - end -end - -module:hook("iq/self/urn:xmpp:pushd_blocking:blocklist", handle_blocking_command); -module:hook("iq/self/urn:xmpp:pushd_blocking:block", handle_blocking_command); -module:hook("iq/self/urn:xmpp:pushd_blocking:unblock", handle_blocking_command); diff --git a/plugins/mod_sipwise_redis_mucs.lua b/plugins/mod_sipwise_redis_mucs.lua deleted file mode 100644 index ebe7997..0000000 --- a/plugins/mod_sipwise_redis_mucs.lua +++ /dev/null @@ -1,154 +0,0 @@ --- Prosody IM --- Copyright (C) 2014-2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- -module:set_global(); -local set = require "util.set"; -local ut = require "ngcp.utils"; -local jid = require "util.jid"; -local redis = require 'redis'; -local redis_config = { - port = 6739, host = "127.0.0.1", - server_id = "0", redis_db = "2" -}; -local redis_client; -local redis_mucs = module:shared("redis_mucs"); - -local function test_connection() - if not redis_client then return nil; end - local ok, _ = pcall(redis_client.ping, redis_client); - if not ok then - redis_client = nil; - end -end - -local function client_connect() - redis_client = redis.connect(redis_config.host, redis_config.port); - if redis_config.redis_db then - redis_client:select(redis_config.redis_db); - end -end - -local function muc_created(event) - local room = event.room; - local rhost = redis_client:get(room.jid); - - if rhost then - module:log("warn", "[%s] already at %s", room.jid, rhost); - return nil; - end - redis_mucs.set_room_host(room.jid, redis_config.server_id); - module:log("debug", "muc-room-created %s", room.jid); -end - -local function muc_pre_restore(event) - local room_jid = event.jid; - local rhost = redis_client:get(room_jid); - - if rhost ~= redis_config.server_id then - module:log("warn", "[%s] already at %s", room_jid, rhost); - return false; - end - module:log("debug", "[%s] already here", room_jid); - return true; -end - -local function muc_restored(event) - local room = event.room; - - redis_mucs.set_room_host(room.jid, redis_config.server_id); - module:log("debug", "muc-room-restored %s", room.jid); -end - -local function muc_destroyed(event) - local room = event.room; - - redis_mucs.clean_room_host(room.jid, redis_config.server_id); - module:log("debug", "muc-room-destroyed %s", room.jid); -end - -local function split_key(key) - local t = ut.explode(':', key); - return t[1], t[2]; -end - -function redis_mucs.get_rooms(host) - local res = set.new(); - local l, r; - - module:log("debug", "search rooms at host[%s]", tostring(host)); - if not test_connection() then client_connect() end - l = redis_client:smembers(host); - - for _,v in pairs(l) do - _, r = split_key(v); - res:add(r..'@'..host); - end - module:log("debug", "found [%s]", tostring(res)); - return res; -end - -function redis_mucs.set_room_host(room_jid, server_id) - local node, host, _ = jid.split(room_jid); - local bare_jid = node.."@"..host; - - if not test_connection() then client_connect() end - -- TODO: check that there is no other "bare_jid" value? - if redis_client:set(bare_jid, server_id) then - module:log("debug", "save [%s]=%s", bare_jid, server_id); - end - if redis_client:sadd(host, server_id..":"..node) > 0 then - module:log("debug", "append [%s]=>%s:%s", host, - server_id, node); - end -end - -function redis_mucs.get_room_host(room_jid) - local node, domain, _ = jid.split(room_jid); - local bare_jid = node.."@"..domain; - - module:log("debug", "search room:%s host", bare_jid); - if not test_connection() then client_connect() end - return redis_client:get(bare_jid); -end - -function redis_mucs.clean_room_host(room_jid, server_id) - local node, host, _ = jid.split(room_jid); - local bare_jid = node.."@"..host; - - if not test_connection() then client_connect() end - if redis_client:del(bare_jid) > 0 then - module:log("debug", "remove [%s]=%s", bare_jid, server_id); - end - if redis_client:srem(host, server_id..":"..node) > 0 then - module:log("debug", "remove [%s]=>%s:%s", host, server_id, node); - end -end - -function module.load() - redis_config = module:get_option("redis_sessions_auth", redis_config); -end - -function shutdown_component() - local rooms = redis_mucs.get_rooms(module:get_host()); - - for room_jid in rooms do - redis_mucs.clean_room_host(room_jid, redis_config.server_id); - end -end -module:hook_global("server-stopping", shutdown_component, -300); - -function module.add_host(module) - local host = module:get_host(); - local _type = module:get_host_type(); - - if _type == "component" then - module:hook("muc-room-created", muc_created, 200); - module:hook("muc-room-destroyed", muc_destroyed, 200); - module:hook("muc-room-restored", muc_restored, 200); - module:hook("muc-room-pre-restore", muc_pre_restore, 200); - end - module:log("debug", "hooked at %s as %s", host, _type); -end diff --git a/plugins/mod_sipwise_redis_sessions.lua b/plugins/mod_sipwise_redis_sessions.lua deleted file mode 100644 index 1ad7079..0000000 --- a/plugins/mod_sipwise_redis_sessions.lua +++ /dev/null @@ -1,141 +0,0 @@ --- Prosody IM --- Copyright (C) 2014-2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -module:set_global(); -local ut = require "ngcp.utils"; -local jid = require "util.jid"; -local array = require "util.array"; -local redis = require 'redis'; -local redis_config = { - port = 6739, host = "127.0.0.1", - server_id = "0", redis_db = "2", - clean_local_sessions = true, -}; -local redis_client; - -local redis_sessions = module:shared("redis_sessions"); - -local function test_connection() - if not redis_client then return nil end; - local ok, _ = pcall(redis_client.ping, redis_client); - if not ok then - redis_client = nil; - end -end - -local function client_connect() - redis_client = redis.connect(redis_config.host, redis_config.port); - --module:log("debug", "connected to redis server %s:%d", - --redis_config.host, redis_config.port); - if redis_config.redis_db then - redis_client:select(redis_config.redis_db); - end -end - -local function resource_bind(event) - local session = event.session; - local node, domain, resource = jid.split(session.full_jid); - local full_jid, bare_jid = session.full_jid, node.."@"..domain; - - module:log("debug", "resource-bind from %s", session.host); - module:log("debug", "save [%s]=%s", full_jid, redis_config.server_id); - if not test_connection() then client_connect() end - redis_client:set(full_jid, redis_config.server_id); - module:log("debug", "append [%s]=>%s:%s", bare_jid, redis_config.server_id, resource); - redis_client:sadd(bare_jid, redis_config.server_id..":"..resource); -end - -local function remove_resource(full_jid) - local node, domain, resource = jid.split(full_jid); - local bare_jid = node.."@"..domain; - - if not test_connection() then client_connect() end - redis_client:del(full_jid); - module:log("debug", "remove [%s]=%s", full_jid, redis_config.server_id); - redis_client:srem(bare_jid, redis_config.server_id..":"..resource); - module:log("debug", "remove [%s]=>%s:%s", bare_jid, - redis_config.server_id, resource); -end - -local function resource_unbind(event) - local session, _ = event.session, event.error; - - module:log("debug", "resource-unbind from %s", session.host); - remove_resource(session.full_jid); -end - -local function split_key(key) - local t = ut.explode(':', key); - return t[1], t[2]; -end - -local function clean_local_sessions(host) - if not test_connection() then client_connect() end - local l = redis_client:keys('*@'..host); - for _, bare_jid in ipairs(l) do - local resources = redis_client:smembers(bare_jid); - module:log("debug", "clean previous sessions for %s on %s", - bare_jid, redis_config.server_id); - for _, resource in ipairs(resources) do - local server, old_resource = split_key(resource); - if server == redis_config.server_id then - module:log("debug", "remove old resource %s", old_resource); - remove_resource(bare_jid..'/'..old_resource); - end - end - end -end - -function redis_sessions.get_hosts(j) - local node, domain = jid.split(j); - local bare_jid = node.."@"..domain; - local res = {}; - local l, h, r; - - module:log("debug", "search session:%s host", bare_jid); - if not test_connection() then client_connect() end - l = redis_client:smembers(bare_jid); - --module:log("debug", "l:%s", ut.table.tostring(l)); - for _,v in pairs(l) do - h, r = split_key(v); - --module:log("debug", "h:%s r:%s", tostring(h), tostring(r)); - if not res[h] then res[h] = array() end - res[h]:push(r); - end - return res; -end - -function redis_sessions.clean_host(j, server_id) - local bare_jid = jid.bare(j); - module:log("debug", "clean jid %s from %s", bare_jid, server_id); - if not test_connection() then client_connect() end - local l = redis_client:smembers(bare_jid); - for _,v in pairs(l) do - local h, _ = split_key(v); - if h == server_id then - redis_client:srem(bare_jid, v); - redis_client:del(v); - module:log("debug", "removed %s from %s", v, bare_jid); - end - end -end - -function module.load() - redis_config = module:get_option("redis_sessions_auth", redis_config); -end - -function module.add_host(module) - local host = module:get_host(); - local _type = module:get_host_type(); - - if _type ~= "component" then - module:hook("resource-bind", resource_bind, 200); - module:hook("resource-unbind", resource_unbind, 200); - clean_local_sessions(host); - end - module:log("debug", "hooked at %s as %s", host, _type); -end diff --git a/plugins/mod_sipwise_vcard_cusax.lua b/plugins/mod_sipwise_vcard_cusax.lua deleted file mode 100644 index f28ea21..0000000 --- a/plugins/mod_sipwise_vcard_cusax.lua +++ /dev/null @@ -1,195 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- Copyright (C) 2013-2015 Sipwise GmbH --- --- This is a stripped down version of mod_vcard for returning --- simply a vcard containing some info of --- the requested user. --- http://xmpp.org/extensions/xep-0054.html --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -local st = require "util.stanza"; -local jid_split = require "util.jid".split; -local vcard = module:shared("vcard"); -local hosts = prosody.hosts; - -local email_query = [[ -SELECT bc.email, bccc.email FROM billing.voip_subscribers AS vs - LEFT join billing.contacts AS bc ON vs.contact_id = bc.id - LEFT join billing.contracts AS bcc ON vs.contract_id = bcc.id - LEFT join billing.contacts AS bccc ON bcc.contact_id = bccc.id - LEFT join billing.domains AS bd ON vs.domain_id = bd.id -WHERE vs.username = ? AND bd.domain = ?; -]] - -local display_usr_query = [[ -SELECT vp.attribute, vup.value FROM provisioning.voip_preferences vp - LEFT JOIN provisioning.voip_usr_preferences vup ON vup.attribute_id = vp.id - LEFT JOIN provisioning.voip_subscribers AS ps ON ps.id = vup.subscriber_id - LEFT JOIN provisioning.voip_domains AS pd ON ps.domain_id = pd.id -WHERE vp.attribute = 'display_name' - AND ps.username = ? AND pd.domain = ? -]]; - -local aliases_query = [[ -SELECT pa.username, pa.is_primary FROM provisioning.voip_dbaliases AS pa - LEFT JOIN provisioning.voip_subscribers AS ps ON ps.id = pa.subscriber_id - LEFT JOIN provisioning.voip_domains AS pd ON ps.domain_id = pd.id -WHERE ps.username = ? AND pd.domain = ? ORDER BY pa.is_primary DESC; -]]; - -local um_user_exists = require "core.usermanager".user_exists; -local sql = require "util.sql"; -local default_params = module:get_option("sql"); -local engine; - -module:add_feature("vcard-temp"); - -local function reconect_check() - if not engine.conn:ping() then - engine.conn = nil; - engine:connect(); - end -end - -function vcard.get_subscriber_info(user, host) - if not hosts[host] or not hosts[host].users then - return nil; - end - if not um_user_exists(user, host) then - return nil; - end - local info = { user = user, domain = host, aliases = {} }; - reconect_check(); - - for row in engine:select(display_usr_query, user, host) do - info['display_name'] = row[2]; - module:log("debug", string.format("display_name:[%s]", row[2])); - end - - for row in engine:select(aliases_query, user, host) do - table.insert(info['aliases'], row[1]); - module:log("debug", string.format("aliases:%s", row[1])); - end - - for row in engine:select(email_query, user, host) do - local email; - -- NULL is not nil here, so checking length - for i= 1, 2 do - if row[i] and row[i]:len() > 0 then - email = row[i]; - break; - end - end - if email then - info['email'] = email; - module:log("debug", "email:", tostring(email)); - end - end - return info; -end - -local function generate_vcard(info) - local function add(t, name, value) - local tmp = st.stanza( name, - { xmlns = "vcard-temp" }); - if value then tmp:text(value) end - if t then - t:add_child(tmp); - else - return tmp; - end - end - local vCard = st.stanza("vCard", - { - xmlns = "vcard-temp", - prodid = "-//HandGen//NONSGML vGen v1.0//EN", - version = "2.0" - } - ); - local uri = info["user"] .. '@' .. info["domain"]; - - add(vCard, "JABBERID", uri); - local t = add(nil, "TEL") - add(t, "VIDEO"); - add(t, "NUMBER", "sip:" .. uri); - vCard:add_child(t); - for _,v in ipairs(info['aliases']) do - t = add(nil, "TEL"); - add(t, "VOICE"); - add(t, "NUMBER", v); - vCard:add_child(t); - end - if info['display_name'] then - add(vCard, "FN", info['display_name']); - end - if info['email'] then - t = add(nil, "EMAIL"); - add(t, "INTERNET"); - add(t, "PREF"); - add(t, "USERID", info['email']); - vCard:add_child(t) - end - return vCard; -end - -local function handle_vcard(event) - module:log("debug", "handle_vcard"); - local session, stanza = event.origin, event.stanza; - local to = stanza.attr.to; - if stanza.attr.type == "get" then - local user, host; - if to then - user, host = jid_split(to); - else - user = session.username; - host = session.host; - end - if not (user and host) then - module:log("error", "bad-request stanza: %s", - tostring(stanza)) - session.send(st.error_reply(stanza, "modify", "jid-malformed")); - end - local info = vcard.get_subscriber_info(user, host); - if info then - local vCard = generate_vcard(info); - local reply = st.reply(stanza):add_child(st.deserialize(vCard)); - session.send(reply); - else - module:log("error", "No info retrieve from stanza: %s", - tostring(stanza)) - session.send(st.error_reply(stanza, "cancel", "item-not-found")); - end - else - module:log("debug", "reject setting vcard"); - session.send(st.error_reply(stanza, "auth", "forbidden")); - end - return true; -end - -module:hook("iq/bare/vcard-temp:vCard", handle_vcard); -module:hook("iq/host/vcard-temp:vCard", handle_vcard); - -local function normalize_params(params) - assert(params.driver and params.database, - "Configuration error: Both the SQL driver and the database need to be specified"); - return params; -end - -function module.load() - if prosody.prosodyctl then return; end - local engines = module:shared("/*/sql/connections"); - local params = normalize_params(module:get_option("auth_sql", default_params)); - engine = engines[sql.db2uri(params)]; - if not engine then - module:log("debug", "Creating new engine"); - engine = sql:create_engine(params); - engines[sql.db2uri(params)] = engine; - end - engine:connect(); - module:log("debug", "load OK"); -end diff --git a/plugins/mod_sipwise_vhosts_sql.lua b/plugins/mod_sipwise_vhosts_sql.lua deleted file mode 100644 index 3dd60b4..0000000 --- a/plugins/mod_sipwise_vhosts_sql.lua +++ /dev/null @@ -1,177 +0,0 @@ --- Load vhosts from DB on startup of Prosody XMPP server. --- Copyright (C) 2013-2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -module:set_global(); - -local DBI = require "DBI" -local nameprep = require "util.encodings".stringprep.nameprep; -local hostmanager = require "core.hostmanager"; -local configmanager = require "core.configmanager"; -local ut = require "ngcp.utils"; -local set = require "util.set"; - -local connection; -local params = module:get_option("auth_sql", module:get_option("sql")); -local prosody = _G.prosody; -local vhosts = set.new(); - -local function test_connection() - module:log("debug", "test_connection"); - if not connection then return nil; end - if connection:ping() then - module:log("debug", "test_connection ok"); - return true; - else - module:log("debug", "Database connection closed"); - connection = nil; - end -end -local function connect() - module:log("debug", "connect"); - if not test_connection() then - prosody.unlock_globals(); - local dbh, err = DBI.Connect( - params.driver, params.database, - params.username, params.password, - params.host, params.port - ); - prosody.lock_globals(); - if not dbh then - module:log("debug", - "Database connection failed: %s", tostring(err)); - return nil, err; - end - module:log("debug", "Successfully connected to database"); - dbh:autocommit(true); -- don't run in transaction - connection = dbh; - return connection; - end -end - -do -- process options to get a db connection - params = params or { driver = "SQLite3" }; - - if params.driver == "SQLite3" then - params.database = configmanager.resolve_relative_path( - prosody.paths.data or ".", - params.database or "prosody.sqlite"); - end - - assert(params.driver and params.database, - "Both the SQL driver and the database need to be specified"); - assert(connect()); -end - -local function getsql(sql, ...) - if params.driver == "PostgreSQL" then - sql = sql:gsub("`", "\""); - end - if not test_connection() then connect(); end - -- do prepared statement stuff - local stmt, err = connection:prepare(sql); - if not stmt and not test_connection() then error("connection failed"); end - if not stmt then - module:log("error", "QUERY FAILED: %s %s", err, debug.traceback()); - return nil, err; - end - -- run query - local ok - ok, err = stmt:execute(...); - if not ok and not test_connection() then error("connection failed"); end - if not ok then return nil, err; end - - return stmt; -end - -local function activate_search(host) - module:log("debug", "activate implicit search.%s", host); - configmanager.set("search."..host, "component_module", - "sipwise_vjud"); - local search_config = configmanager.getconfig()["search."..host]; - hostmanager.activate("search."..host, search_config); -end - -local function activate_muc(host) - local host_modules = configmanager.get(host, "modules_enabled"); - local conference_modules = {}; - - module:log("debug", "modules_enabled[%s]: %s", host, - ut.table.tostring(host_modules)); - - configmanager.set("conference."..host, "component_module", - "muc"); - if ut.table.contains(host_modules, "shard") then - ut.table.add(conference_modules, "sipwise_redis_mucs"); - ut.table.add(conference_modules, "shard"); - end - if ut.table.contains(host_modules, "sipwise_pushd") then - ut.table.add(conference_modules, "sipwise_pushd"); - end - if ut.table.contains(host_modules, "mam") then - ut.table.add(conference_modules, "muc_mam"); - end - module:log("debug", "conference_modules[%s]: %s", - "conference."..host, ut.table.tostring(host_modules)); - configmanager.set("conference."..host, "modules_enabled", - conference_modules); - local conference_config = configmanager.getconfig()["conference."..host]; - conference_config['restrict_room_creation'] = 'local'; - hostmanager.activate("conference."..host, conference_config); - module:log("debug", "modules_enabled[%s]: %s", "conference."..host, - ut.table.tostring(conference_config['modules_enabled'])); -end - -local function add_vhost(host) - local host_config = { enable = true }; - - module:log("debug", "activate host %s", host); - vhosts:add(host); - hostmanager.activate(host, host_config); - - activate_search(host); - activate_muc(host); -end - -local function load_vhosts_from_db() - local stmt, _ = getsql("SELECT `domain` FROM `domain`"); - if stmt then - for row in stmt:rows(true) do - local host = nameprep(row.domain); - add_vhost(host); - end - end -end - -local function check_vhosts(host) - if ut.string.starts(host, 'search.') or - ut.string.starts(host, 'conference.') or - vhosts:contains(host) then - module:log("debug", "%s activated, nothing to do", host); - return - end - module:log("info", "%s activate subdomains", host); - activate_search(host); - activate_muc(host); - vhosts:add(host); -end - -local function deactivate_vhost(host) - if ut.string.starts(host, 'search.') or - ut.string.starts(host, 'conference.') or - not vhosts:contains(host) then - module:log("debug", "%s deactivated, nothing to do", host); - return - end - module:log("info", "%s deactivate subdomains", host); - hostmanager.deactivate("search."..host, 'main domain deactivated'); - hostmanager.deactivate("conference."..host, 'main domain deactivated'); - vhosts:remove(host); -end - -module:hook("server-started", load_vhosts_from_db); -module:hook("host-activated", check_vhosts); -module:hook("host-deactivated", deactivate_vhost); diff --git a/plugins/mod_sipwise_vjud.lua b/plugins/mod_sipwise_vjud.lua deleted file mode 100644 index 85af47d..0000000 --- a/plugins/mod_sipwise_vjud.lua +++ /dev/null @@ -1,336 +0,0 @@ --- --- Copyright (C) 2013-2015 Sipwise GmbH --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- -module:depends("disco"); -local softreq = require "util.dependencies".softreq; -local ut_jid = require "util.jid"; -local sql = require "util.sql"; -local st = require "util.stanza"; -local template = require "util.template"; -local prosodyctl = require "util.prosodyctl" -local dataforms_new = require "util.dataforms".new; -local ut = require "ngcp.utils"; -local hosts = prosody.hosts; -local rex = softreq "rex_pcre"; -if not rex then - rex = require "rex_pcre2"; -end - -local form_layout = dataforms_new{ - title= 'User Directory Search'; - instructions = 'Please provide the following information to search for subscribers'; - { - type = 'text-single', - label = 'e164 Phone number', - name = 'e164', - required = false, - }, - { - type = 'text-single', - label = 'domain', - name = 'domain', - required = false, - }, -}; - -local form_item = template[[ - - - {value} - - -]]; - -local form_reply = { - domain = template[[ - - - - jabber:iq:search - - - - - - -]], - e164 = template[[ - - - - jabber:iq:search - - - - - - -]], - form = template[[ - - Use the enclosed form to search - - User Directory Search - Please provide the following information to search for subscribers - - jabber:iq:search - - - - - - -]] -}; - -local usr_replacements_query = [[ -SELECT vrr.match_pattern, vrr.replace_pattern FROM provisioning.voip_preferences vp - LEFT JOIN provisioning.voip_usr_preferences vup ON vup.attribute_id = vp.id - LEFT JOIN provisioning.voip_subscribers vs ON vs.id = vup.subscriber_id - LEFT JOIN provisioning.voip_domains vd ON vd.id = vs.domain_id - LEFT JOIN provisioning.voip_rewrite_rule_sets vrrs ON vrrs.callee_in_dpid = vup.value - LEFT JOIN provisioning.voip_rewrite_rules vrr ON vrr.set_id = vrrs.id - AND vrr.direction = 'in' - AND vrr.field = 'callee' -WHERE vp.attribute = 'rewrite_callee_in_dpid' AND vs.username = ? AND vd.domain = ? - ORDER BY vrr.priority ASC; -]]; - -local dom_replacements_query = [[ -SELECT vrr.match_pattern, vrr.replace_pattern FROM provisioning.voip_preferences vp - LEFT JOIN provisioning.voip_dom_preferences vdp ON vdp.attribute_id = vp.id - LEFT JOIN provisioning.voip_domains vd ON vd.id = vdp.domain_id - LEFT JOIN provisioning.voip_rewrite_rule_sets vrrs ON vrrs.callee_in_dpid = vdp.value - LEFT JOIN provisioning.voip_rewrite_rules vrr ON vrr.set_id = vrrs.id - AND vrr.direction = 'in' AND vrr.field = 'callee' -WHERE vp.attribute = 'rewrite_callee_in_dpid' AND vd.domain = ? - ORDER BY vrr.priority ASC; -]]; - -local locale_query = [[ -SELECT vp.attribute, vup.value FROM provisioning.voip_preferences vp - LEFT JOIN provisioning.voip_usr_preferences vup ON vup.attribute_id = vp.id - LEFT JOIN provisioning.voip_subscribers vs ON vs.id = vup.subscriber_id - LEFT JOIN provisioning.voip_domains vd ON vd.id = vs.domain_id -WHERE (vp.attribute = 'ac' or vp.attribute = 'cc') - AND vs.username = ? - AND vd.domain = ?; -]]; - -local lookup_query = [[ -SELECT username,domain FROM kamailio.dbaliases -WHERE alias_username=?; -]]; - -local default_params = module:get_option("sql"); -local engine; - --- Reconnect to DB if necessary -local function reconect_check() - if not engine.conn:ping() then - engine.conn = nil; - engine:connect(); - end -end - -local function normalize_number(user, host, number) - local locale_info = {}; - reconect_check(); - for row in engine:select(locale_query, user, host) do - locale_info["caller_"..row[1]] = row[2]; - end - - local replacement_regexes = {}; - local usr_pref = 0; - for row in engine:select(usr_replacements_query, user, host) do - usr_pref = 1; - module:log("debug", "user rewrite_callee_in_dpid preference found"); - local patt, repl = row[1], row[2] - :gsub("%$avp%(s:([a-zA-Z_]+)%)", locale_info) - :gsub("\\", "%%"):gsub("%%%%", "\\"); - table.insert(replacement_regexes, { patt, repl }); - end - if usr_pref == 0 then - for row in engine:select(dom_replacements_query, host) do - module:log("debug", "domain rewrite_callee_in_dpid preference found"); - local patt, repl = row[1], row[2] - :gsub("%$avp%(s:([a-zA-Z_]+)%)", locale_info) - :gsub("\\", "%%"):gsub("%%%%", "\\"); - table.insert(replacement_regexes, { patt, repl }); - end - end - - for _, rule in ipairs(replacement_regexes) do - local new_number, n_matches = rex.gsub(number, rule[1], rule[2]); - if n_matches > 0 then - module:log("debug", "rule [%s] matched [%s]->[%s]", - tostring(rule[1]), tostring(number), tostring(new_number)); - number = new_number; - break; - end - end - return number; -end - -local function search_by_number(number) - local results = {}; - reconect_check(); - module:log("debug", "search jids with number:[%s]", tostring(number)); - for result in engine:select(lookup_query, number) do - table.insert(results, result[1].."@"..result[2]); - end - return results; -end - -local function get_dataform_items(vals, fieldname) - local res = {}; - - for _,v in ipairs(vals) do - table.insert(res, form_item.apply({ name = fieldname, value = v })); - end - return res; -end - -local function search_domains(dom) - local hosts_keys = ut.table.keys(hosts); - local res = {}; - - module:log("debug", "search for domain: %s", tostring(dom)); - if dom == '*' then - res = get_dataform_items(hosts_keys, 'domain'); - elseif ut.table.contains(hosts_keys, dom) then - res = get_dataform_items({dom,}, 'domain'); - end - return res; -end - -function module.command(arg) - local warn = prosodyctl.show_warning; - local command = arg[1]; - if not command then - warn("Valid subcommands: normalize"); - return 0; - end - table.remove(arg, 1); - if command == "normalize" then - if #arg ~= 2 then - warn("Usage: normalize USER@HOST NUMBER"); - return 1; - end - local user_jid, number = arg[1], arg[2]; - local user, host = ut_jid.prepped_split(user_jid); - if not (user and host) then - warn("Invalid JID: "..user_jid); - return 1; - end - print(normalize_number(user, host, number)); - elseif command == "query" then - if #arg ~= 1 then - warn("Usage: query NUMBER"); - warn(" NUMBER must be normalized (see 'normalize' command)"); - return 1; - end - local results = search_by_number(arg[1]); - for _, jid in ipairs(results) do - print("", jid); - end - end - return 0; -end - -local function append_x_items(form, values, reply) - local x = form:get_child('x', 'jabber:x:data'); - for _, v in ipairs(values) do - x:add_child(v):up(); - end - reply:add_child(x); -end - -if module:get_host_type() ~= "component" then - error("Don't load mod_sipwise_vjud manually,".. - " it should be for a component", 0); -end - -module:add_feature("jabber:iq:search"); -module:add_feature("jabber:x:data"); -- dataforms -module:hook("iq/host/jabber:iq:search:query", function(event) - local origin, stanza = event.origin, event.stanza; - module:log("debug", "stanza[%s]", tostring(stanza)); - if stanza.attr.type == "get" then - return origin.send(st.reply(stanza):add_child(form_reply.form.apply({}))); - else - - local user, host = ut_jid.split(stanza.attr.from); - local query = stanza:get_child("query",'jabber:iq:search'); - local form_stanza = query:get_child("x",'jabber:x:data'); - local reply; - local search_number = stanza.tags[1]:get_child_text("nick"); - local search_domain - - if form_stanza then - local form_data, form_errors = form_layout:data(form_stanza); - if form_errors and form_errors['e164'] then - reply = st.error_reply(stanza, "modify", - "bad-request", "e164: "..form_errors['e164']); - return origin.send(reply); - else - search_number = form_data['e164'] or search_number; - search_domain = form_data['domain']; - end - end - - if search_number then - local number = normalize_number(user, host, search_number); - local data = search_by_number(number); - reply = st.reply(stanza):query("jabber:iq:search"); - if form_stanza then - append_x_items(form_reply.e164.apply({}), - get_dataform_items(data, 'e164'), reply); - else - for _, jid in ipairs(data) do - reply:tag("item", { jid = jid }):up(); - end - end - elseif search_domain then - reply = st.reply(stanza):query("jabber:iq:search"); - append_x_items(form_reply.domain.apply({}), - search_domains(search_domain), reply); - else - reply = st.error_reply(stanza, "modify", - "bad-request", "no domain, nick or e164 field found"); - end - - return origin.send(reply); - end -end); - -local function normalize_params(params) - assert(params.driver and params.database, - "Configuration error: Both the SQL driver and the database need to be specified"); - return params; -end - -function module.load() - if prosody.prosodyctl then return; end - local engines = module:shared("/*/sql/connections"); - local params = normalize_params(module:get_option("auth_sql", default_params)); - engine = engines[sql.db2uri(params)]; - if not engine then - module:log("debug", "Creating new engine"); - engine = sql:create_engine(params); - engines[sql.db2uri(params)] = engine; - end - engine:connect(); - module:log("debug", "load OK"); -end diff --git a/plugins/mod_smacks/README.markdown b/plugins/mod_smacks/README.markdown deleted file mode 100644 index 9326e6e..0000000 --- a/plugins/mod_smacks/README.markdown +++ /dev/null @@ -1,91 +0,0 @@ ---- -labels: -- 'Stage-Alpha' -summary: 'XEP-0198: Reliability and fast reconnects for XMPP' -... - -Introduction -============ - -By default XMPP is as reliable as your network is. Unfortunately in some -cases that is not very reliable - in some network conditions disconnects -can be frequent and message loss can occur. - -To overcome this, XMPP has an optional extension (XEP-0198: Stream -Management) which, when supported by both the client and server, can -allow a client to resume a disconnected session, and prevent message -loss. - -Details -======= - -When using XEP-0198 both the client and the server keep a queue of the -most recently sent stanzas - this is cleared when the other end -acknowledges they have received the stanzas. If the client disconnects, -instead of marking the user offline the server pretends the client is -still online for a short (configurable) period of time. If the client -reconnects within this period, any stanzas in the queue that the client -did not receive are re-sent. - -If the client fails to reconnect before the timeout it will be marked as -offline like prosody does on disconnect without mod_smacks. -If the client is the last one for this jid, all message stanzas are added to -the offline store and all other stanzas stanzas are returned with an -"recipient-unavailable" error. If the client is not the last one with an -open smacks session, *all* stanzas are returned with an "recipient-unavailable" error. - -If you deliberately disabled [mod_offline], all message stanzas of the last client -are also returned with an "recipient-unavailable" error, because the can not be -added to the offline storage. -If you don't want this behaviour you can use [mod_nooffline_noerror] to suppress the error. -This is generally only advisable, if you are sure that all your clients are using MAM! - -This module also provides some events used by [mod_cloud_notify]. -These events are: "smacks-ack-delayed", "smacks-hibernation-start" and -"smacks-hibernation-end". See [mod_cloud_notify] for details on how this -events are used there. - -Use prosody 0.10+ to have per user limits on allowed sessions in hibernation -state and allowed sessions for which the h-value is kept even after the -hibernation timed out. -These are settable using `smacks_max_hibernated_sessions` and `smacks_max_old_sessions`. - -Configuration -============= - - Option Default Description - ---------------------------------- ----------------- ------------------------------------------------------------------------------------------------------------------ - `smacks_hibernation_time` 600 (10 minutes) The number of seconds a disconnected session should stay alive for (to allow reconnect) - `smacks_enabled_s2s` true Enable Stream Management on server connections? *Experimental* - `smacks_s2s_resend` false Attempt to re-send unacked messages on s2s disconnect *Experimental* - `smacks_max_unacked_stanzas` 0 How many stanzas to send before requesting acknowledgement - `smacks_max_ack_delay` 30 (1/2 minute) The number of seconds an ack must be unanswered to trigger an "smacks-ack-delayed" event - `smacks_max_hibernated_sessions` 10 The number of allowed sessions in hibernated state (limited per user) - `smacks_max_old_sessions` 10 The number of allowed sessions with timed out hibernation for which the h-value is still kept (limited per user) - -Compatibility -============= - - ------- ------- - trunk Works - 0.11 Works - ------- ------- - - -Clients -======= - -Clients that support [XEP-0198]: - -- Gajim (Linux, Windows, OS X) -- Conversations (Android) -- ChatSecure (iOS) -- Swift (but not resumption, as of version 2.0 and alphas of 3.0) -- Psi (in an unreleased branch) -- Yaxim (Android) -- Monal (iOS) - -[7693724881b3]: //hg.prosody.im/prosody-modules/raw-file/7693724881b3/mod_smacks/mod_smacks.lua -[mod_offline]: //modules.prosody.im/mod_offline -[mod_nooffline_noerror]: //modules.prosody.im/mod_nooffline_noerror -[mod_cloud_notify]: //modules.prosody.im/mod_cloud_notify diff --git a/plugins/mod_smacks/mod_smacks.lua b/plugins/mod_smacks/mod_smacks.lua deleted file mode 100644 index 96c4a18..0000000 --- a/plugins/mod_smacks/mod_smacks.lua +++ /dev/null @@ -1,690 +0,0 @@ --- XEP-0198: Stream Management for Prosody IM --- --- Copyright (C) 2010-2015 Matthew Wild --- Copyright (C) 2010 Waqas Hussain --- Copyright (C) 2012-2021 Kim Alvefur --- Copyright (C) 2012 Thijs Alkemade --- Copyright (C) 2014 Florian Zeitz --- Copyright (C) 2016-2020 Thilo Molitor --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -local st = require "util.stanza"; -local dep = require "util.dependencies"; -local cache = dep.softreq("util.cache"); -- only available in prosody 0.10+ -local uuid_generate = require "util.uuid".generate; -local jid = require "util.jid"; - -local t_remove = table.remove; -local math_min = math.min; -local math_max = math.max; -local os_time = os.time; -local tonumber, tostring = tonumber, tostring; -local add_filter = require "util.filters".add_filter; -local timer = require "util.timer"; -local datetime = require "util.datetime"; - -local xmlns_mam2 = "urn:xmpp:mam:2"; -local xmlns_sm2 = "urn:xmpp:sm:2"; -local xmlns_sm3 = "urn:xmpp:sm:3"; -local xmlns_errors = "urn:ietf:params:xml:ns:xmpp-stanzas"; -local xmlns_delay = "urn:xmpp:delay"; - -local sm2_attr = { xmlns = xmlns_sm2 }; -local sm3_attr = { xmlns = xmlns_sm3 }; - -local resume_timeout = module:get_option_number("smacks_hibernation_time", 600); -local s2s_smacks = module:get_option_boolean("smacks_enabled_s2s", true); -local s2s_resend = module:get_option_boolean("smacks_s2s_resend", false); -local max_unacked_stanzas = module:get_option_number("smacks_max_unacked_stanzas", 0); -local max_inactive_unacked_stanzas = module:get_option_number("smacks_max_inactive_unacked_stanzas", 256); -local delayed_ack_timeout = module:get_option_number("smacks_max_ack_delay", 30); -local max_hibernated_sessions = module:get_option_number("smacks_max_hibernated_sessions", 10); -local max_old_sessions = module:get_option_number("smacks_max_old_sessions", 10); -local core_process_stanza = prosody.core_process_stanza; -local sessionmanager = require"core.sessionmanager"; - -assert(max_hibernated_sessions > 0, "smacks_max_hibernated_sessions must be greater than 0"); -assert(max_old_sessions > 0, "smacks_max_old_sessions must be greater than 0"); - -local c2s_sessions = module:shared("/*/c2s/sessions"); - -local function init_session_cache(max_entries, evict_callback) - -- old prosody version < 0.10 (no limiting at all!) - if not cache then - local store = {}; - return { - get = function(user, key) - if not user then return nil; end - if not key then return nil; end - return store[key]; - end; - set = function(user, key, value) - if not user then return nil; end - if not key then return nil; end - store[key] = value; - end; - }; - end - - -- use per user limited cache for prosody >= 0.10 - local stores = {}; - return { - get = function(user, key) - if not user then return nil; end - if not key then return nil; end - if not stores[user] then - stores[user] = cache.new(max_entries, evict_callback); - end - return stores[user]:get(key); - end; - set = function(user, key, value) - if not user then return nil; end - if not key then return nil; end - if not stores[user] then stores[user] = cache.new(max_entries, evict_callback); end - stores[user]:set(key, value); - -- remove empty caches completely - if not stores[user]:count() then stores[user] = nil; end - end; - }; -end -local old_session_registry = init_session_cache(max_old_sessions, nil); -local session_registry = init_session_cache(max_hibernated_sessions, function(resumption_token, session) - if session.destroyed then return true; end -- destroyed session can always be removed from cache - session.log("warn", "User has too much hibernated sessions, removing oldest session (token: %s)", resumption_token); - -- store old session's h values on force delete - -- save only actual h value and username/host (for security) - old_session_registry.set(session.username, resumption_token, { - h = session.handled_stanza_count, - username = session.username, - host = session.host - }); - return true; -- allow session to be removed from full cache to make room for new one -end); - -local function stoppable_timer(delay, callback) - local stopped = false; - local timer = module:add_timer(delay, function (t) - if stopped then return; end - return callback(t); - end); - if timer and timer.stop then return timer; end -- new prosody api includes stop() function - return { - stop = function(self) stopped = true end; - timer; - }; -end - -local function delayed_ack_function(session, stanza) - -- fire event only if configured to do so and our session is not already hibernated or destroyed - if delayed_ack_timeout > 0 and session.awaiting_ack - and not session.hibernating and not session.destroyed then - session.log("debug", "Firing event 'smacks-ack-delayed', queue = %d", - session.outgoing_stanza_queue and #session.outgoing_stanza_queue or 0); - module:fire_event("smacks-ack-delayed", {origin = session, queue = session.outgoing_stanza_queue, stanza = stanza}); - end - session.delayed_ack_timer = nil; -end - -local function can_do_smacks(session, advertise_only) - if session.smacks then return false, "unexpected-request", "Stream management is already enabled"; end - - local session_type = session.type; - if session.username then - if not(advertise_only) and not(session.resource) then -- Fail unless we're only advertising sm - return false, "unexpected-request", "Client must bind a resource before enabling stream management"; - end - return true; - elseif s2s_smacks and (session_type == "s2sin" or session_type == "s2sout") then - return true; - end - return false, "service-unavailable", "Stream management is not available for this stream"; -end - -module:hook("stream-features", - function (event) - if can_do_smacks(event.origin, true) then - event.features:tag("sm", sm2_attr):tag("optional"):up():up(); - event.features:tag("sm", sm3_attr):tag("optional"):up():up(); - end - end); - -module:hook("s2s-stream-features", - function (event) - if can_do_smacks(event.origin, true) then - event.features:tag("sm", sm2_attr):tag("optional"):up():up(); - event.features:tag("sm", sm3_attr):tag("optional"):up():up(); - end - end); - -local function request_ack_if_needed(session, force, reason, stanza) - local queue = session.outgoing_stanza_queue; - local expected_h = session.last_acknowledged_stanza + #queue; - -- session.log("debug", "*** SMACKS(1) ***: awaiting_ack=%s, hibernating=%s", tostring(session.awaiting_ack), tostring(session.hibernating)); - local max_unacked = max_unacked_stanzas; - if session.state == "inactive" then - max_unacked = max_inactive_unacked_stanzas; - end - if session.awaiting_ack == nil and not session.hibernating then - -- this check of last_requested_h prevents ack-loops if missbehaving clients report wrong - -- stanza counts. it is set when an is really sent (e.g. inside timer), preventing any - -- further requests until a higher h-value would be expected. - -- session.log("debug", "*** SMACKS(2) ***: #queue=%s, max_unacked_stanzas=%s, expected_h=%s, last_requested_h=%s", tostring(#queue), tostring(max_unacked_stanzas), tostring(expected_h), tostring(session.last_requested_h)); - if (#queue > max_unacked and expected_h ~= session.last_requested_h) or force then - session.log("debug", "Queuing (in a moment) from %s - #queue=%d", reason, #queue); - session.awaiting_ack = false; - session.awaiting_ack_timer = stoppable_timer(1e-06, function () - -- session.log("debug", "*** SMACKS(3) ***: awaiting_ack=%s, hibernating=%s", tostring(session.awaiting_ack), tostring(session.hibernating)); - -- only request ack if needed and our session is not already hibernated or destroyed - if not session.awaiting_ack and not session.hibernating and not session.destroyed then - session.log("debug", "Sending (inside timer, before send) from %s - #queue=%d", reason, #queue); - (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })) - if session.destroyed then return end -- sending something can trigger destruction - session.awaiting_ack = true; - -- expected_h could be lower than this expression e.g. more stanzas added to the queue meanwhile) - session.last_requested_h = session.last_acknowledged_stanza + #queue; - session.log("debug", "Sending (inside timer, after send) from %s - #queue=%d", reason, #queue); - if not session.delayed_ack_timer then - session.delayed_ack_timer = stoppable_timer(delayed_ack_timeout, function() - delayed_ack_function(session, nil); -- we don't know if this is the only new stanza in the queue - end); - end - end - end); - end - end - - -- Trigger "smacks-ack-delayed"-event if we added new (ackable) stanzas to the outgoing queue - -- and there isn't already a timer for this event running. - -- If we wouldn't do this, stanzas added to the queue after the first "smacks-ack-delayed"-event - -- would not trigger this event (again). - if #queue > max_unacked and session.awaiting_ack and session.delayed_ack_timer == nil then - session.log("debug", "Calling delayed_ack_function directly (still waiting for ack)"); - delayed_ack_function(session, stanza); -- this is the only new stanza in the queue --> provide it to other modules - end -end - -local function outgoing_stanza_filter(stanza, session) - -- XXX: Normally you wouldn't have to check the xmlns for a stanza as it's - -- supposed to be nil. - -- However, when using mod_smacks with mod_websocket, then mod_websocket's - -- stanzas/out filter can get called before this one and adds the xmlns. - local is_stanza = stanza.attr and - (not stanza.attr.xmlns or stanza.attr.xmlns == 'jabber:client') - and not stanza.name:find":"; - - if is_stanza and not stanza._cached then - local queue = session.outgoing_stanza_queue; - local cached_stanza = st.clone(stanza); - cached_stanza._cached = true; - - if cached_stanza and cached_stanza.name ~= "iq" and cached_stanza:get_child("delay", xmlns_delay) == nil then - cached_stanza = cached_stanza:tag("delay", { - xmlns = xmlns_delay, - from = jid.bare(session.full_jid or session.host), - stamp = datetime.datetime() - }); - end - - queue[#queue+1] = cached_stanza; - if session.hibernating then - session.log("debug", "hibernating since %s, stanza queued", datetime.datetime(session.hibernating)); - module:fire_event("smacks-hibernation-stanza-queued", {origin = session, queue = queue, stanza = cached_stanza}); - return nil; - end - request_ack_if_needed(session, false, "outgoing_stanza_filter", stanza); - end - return stanza; -end - -local function count_incoming_stanzas(stanza, session) - if not stanza.attr.xmlns then - session.handled_stanza_count = session.handled_stanza_count + 1; - session.log("debug", "Handled %d incoming stanzas", session.handled_stanza_count); - end - return stanza; -end - -local function wrap_session_out(session, resume) - if not resume then - session.outgoing_stanza_queue = {}; - session.last_acknowledged_stanza = 0; - end - - add_filter(session, "stanzas/out", outgoing_stanza_filter, -999); - - local session_close = session.close; - function session.close(...) - if session.resumption_token then - session_registry.set(session.username, session.resumption_token, nil); - old_session_registry.set(session.username, session.resumption_token, nil); - session.resumption_token = nil; - end - -- send out last ack as per revision 1.5.2 of XEP-0198 - if session.smacks and session.conn and session.handled_stanza_count then - (session.sends2s or session.send)(st.stanza("a", { xmlns = session.smacks, h = string.format("%d", session.handled_stanza_count) })); - end - return session_close(...); - end - return session; -end - -local function wrap_session_in(session, resume) - if not resume then - session.handled_stanza_count = 0; - end - add_filter(session, "stanzas/in", count_incoming_stanzas, 999); - - return session; -end - -local function wrap_session(session, resume) - wrap_session_out(session, resume); - wrap_session_in(session, resume); - return session; -end - -function handle_enable(session, stanza, xmlns_sm) - local ok, err, err_text = can_do_smacks(session); - if not ok then - session.log("warn", "Failed to enable smacks: %s", err_text); -- TODO: XEP doesn't say we can send error text, should it? - (session.sends2s or session.send)(st.stanza("failed", { xmlns = xmlns_sm }):tag(err, { xmlns = xmlns_errors})); - return true; - end - - module:log("debug", "Enabling stream management"); - session.smacks = xmlns_sm; - - wrap_session(session, false); - - local resume_token; - local resume = stanza.attr.resume; - if resume == "true" or resume == "1" then - resume_token = uuid_generate(); - session_registry.set(session.username, resume_token, session); - session.resumption_token = resume_token; - end - (session.sends2s or session.send)(st.stanza("enabled", { xmlns = xmlns_sm, id = resume_token, resume = resume, max = tostring(resume_timeout) })); - return true; -end -module:hook_stanza(xmlns_sm2, "enable", function (session, stanza) return handle_enable(session, stanza, xmlns_sm2); end, 100); -module:hook_stanza(xmlns_sm3, "enable", function (session, stanza) return handle_enable(session, stanza, xmlns_sm3); end, 100); - -module:hook_stanza("http://etherx.jabber.org/streams", "features", - function (session, stanza) - stoppable_timer(1e-6, function () - if can_do_smacks(session) then - if stanza:get_child("sm", xmlns_sm3) then - session.sends2s(st.stanza("enable", sm3_attr)); - session.smacks = xmlns_sm3; - elseif stanza:get_child("sm", xmlns_sm2) then - session.sends2s(st.stanza("enable", sm2_attr)); - session.smacks = xmlns_sm2; - else - return; - end - wrap_session_out(session, false); - end - end); - end); - -function handle_enabled(session, stanza, xmlns_sm) - module:log("debug", "Enabling stream management"); - session.smacks = xmlns_sm; - - wrap_session_in(session, false); - - -- FIXME Resume? - - return true; -end -module:hook_stanza(xmlns_sm2, "enabled", function (session, stanza) return handle_enabled(session, stanza, xmlns_sm2); end, 100); -module:hook_stanza(xmlns_sm3, "enabled", function (session, stanza) return handle_enabled(session, stanza, xmlns_sm3); end, 100); - -function handle_r(origin, stanza, xmlns_sm) - if not origin.smacks then - module:log("debug", "Received ack request from non-smack-enabled session"); - return; - end - module:log("debug", "Received ack request, acking for %d", origin.handled_stanza_count); - -- Reply with - (origin.sends2s or origin.send)(st.stanza("a", { xmlns = xmlns_sm, h = string.format("%d", origin.handled_stanza_count) })); - -- piggyback our own ack request if needed (see request_ack_if_needed() for explanation of last_requested_h) - local expected_h = origin.last_acknowledged_stanza + #origin.outgoing_stanza_queue; - if #origin.outgoing_stanza_queue > 0 and expected_h ~= origin.last_requested_h then - request_ack_if_needed(origin, true, "piggybacked by handle_r", nil); - end - return true; -end -module:hook_stanza(xmlns_sm2, "r", function (origin, stanza) return handle_r(origin, stanza, xmlns_sm2); end); -module:hook_stanza(xmlns_sm3, "r", function (origin, stanza) return handle_r(origin, stanza, xmlns_sm3); end); - -function handle_a(origin, stanza) - if not origin.smacks then return; end - origin.awaiting_ack = nil; - if origin.awaiting_ack_timer then - origin.awaiting_ack_timer:stop(); - end - if origin.delayed_ack_timer then - origin.delayed_ack_timer:stop(); - origin.delayed_ack_timer = nil; - end - -- Remove handled stanzas from outgoing_stanza_queue - -- origin.log("debug", "ACK: h=%s, last=%s", stanza.attr.h or "", origin.last_acknowledged_stanza or ""); - local h = tonumber(stanza.attr.h); - if not h then - origin:close{ condition = "invalid-xml"; text = "Missing or invalid 'h' attribute"; }; - return; - end - local handled_stanza_count = h-origin.last_acknowledged_stanza; - local queue = origin.outgoing_stanza_queue; - if handled_stanza_count > #queue then - origin.log("warn", "The client says it handled %d new stanzas, but we only sent %d :)", - handled_stanza_count, #queue); - origin.log("debug", "Client h: %d, our h: %d", tonumber(stanza.attr.h), origin.last_acknowledged_stanza); - for i=1,#queue do - origin.log("debug", "Q item %d: %s", i, tostring(queue[i])); - end - origin:close{ condition = "undefined-condition"; text = "Client acknowledged more stanzas than sent by server"; }; - return; - end - - for i=1,math_min(handled_stanza_count,#queue) do - local handled_stanza = t_remove(origin.outgoing_stanza_queue, 1); - module:fire_event("delivery/success", { session = origin, stanza = handled_stanza }); - end - - origin.log("debug", "#queue = %d", #queue); - origin.last_acknowledged_stanza = origin.last_acknowledged_stanza + handled_stanza_count; - request_ack_if_needed(origin, false, "handle_a", nil) - return true; -end -module:hook_stanza(xmlns_sm2, "a", handle_a); -module:hook_stanza(xmlns_sm3, "a", handle_a); - ---TODO: Optimise... incoming stanzas should be handled by a per-session --- function that has a counter as an upvalue (no table indexing for increments, --- and won't slow non-198 sessions). We can also then remove the .handled flag --- on stanzas - -local function handle_unacked_stanzas(session) - local queue = session.outgoing_stanza_queue; - local error_attr = { type = "cancel" }; - if #queue > 0 then - session.outgoing_stanza_queue = {}; - for i=1,#queue do - if not module:fire_event("delivery/failure", { session = session, stanza = queue[i] }) then - if queue[i].attr.type ~= "error" then - local reply = st.reply(queue[i]); - if reply.attr.to ~= session.full_jid then - reply.attr.type = "error"; - reply:tag("error", error_attr) - :tag("recipient-unavailable", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}); - core_process_stanza(session, reply); - end - end - end - end - end -end - --- don't send delivery errors for messages which will be delivered by mam later on --- check if stanza was archived --> this will allow us to send back errors for stanzas not archived --- because the user configured the server to do so ("no-archive"-setting for one special contact for example) -local function get_stanza_id(stanza, by_jid) - for tag in stanza:childtags("stanza-id", "urn:xmpp:sid:0") do - if tag.attr.by == by_jid then - return tag.attr.id; - end - end - return nil; -end -module:hook("delivery/failure", function(event) - local session, stanza = event.session, event.stanza; - -- Only deal with authenticated (c2s) sessions - if session.username then - if stanza.name == "message" and stanza.attr.xmlns == nil and - ( stanza.attr.type == "chat" or ( stanza.attr.type or "normal" ) == "normal" ) then - -- don't store messages in offline store if they are mam results - local mam_result = stanza:get_child("result", xmlns_mam2); - if mam_result ~= nil then - return true; -- stanza already "handled", don't send an error and don't add it to offline storage - end - -- do nothing here for normal messages and don't send out "message delivery errors", - -- because messages are already in MAM at this point (no need to frighten users) - local stanza_id = get_stanza_id(stanza, jid.bare(session.full_jid)); - if session.mam_requested and stanza_id ~= nil then - session.log("debug", "mod_smacks delivery/failure returning true for mam-handled stanza: mam-archive-id=%s", tostring(stanza_id)); - return true; -- stanza handled, don't send an error - end - -- store message in offline store, if this client does not use mam *and* was the last client online - local sessions = prosody.hosts[module.host].sessions[session.username] and - prosody.hosts[module.host].sessions[session.username].sessions or nil; - if sessions and next(sessions) == session.resource and next(sessions, session.resource) == nil then - local ok = module:fire_event("message/offline/handle", { origin = session, username = session.username, stanza = stanza }); - session.log("debug", "mod_smacks delivery/failuere returning %s for offline-handled stanza", tostring(ok)); - return ok; -- if stanza was handled, don't send an error - end - end - end -end); - -module:hook("pre-resource-unbind", function (event) - local session, err = event.session, event.error; - if session.smacks then - if not session.resumption_token then - local queue = session.outgoing_stanza_queue; - if #queue > 0 then - session.log("debug", "Destroying session with %d unacked stanzas", #queue); - handle_unacked_stanzas(session); - end - else - session.log("debug", "mod_smacks hibernating session for up to %d seconds", resume_timeout); - local hibernate_time = os_time(); -- Track the time we went into hibernation - session.hibernating = hibernate_time; - local resumption_token = session.resumption_token; - module:fire_event("smacks-hibernation-start", {origin = session, queue = session.outgoing_stanza_queue}); - timer.add_task(resume_timeout, function () - session.log("debug", "mod_smacks hibernation timeout reached..."); - -- We need to check the current resumption token for this resource - -- matches the smacks session this timer is for in case it changed - -- (for example, the client may have bound a new resource and - -- started a new smacks session, or not be using smacks) - local curr_session = full_sessions[session.full_jid]; - if session.destroyed then - session.log("debug", "The session has already been destroyed"); - elseif curr_session and curr_session.resumption_token == resumption_token - -- Check the hibernate time still matches what we think it is, - -- otherwise the session resumed and re-hibernated. - and session.hibernating == hibernate_time then - -- wait longer if the timeout isn't reached because push was enabled for this session - -- session.first_hibernated_push is the starting point for hibernation timeouts of those push enabled clients - -- wait for an additional resume_timeout seconds if no push occurred since hibernation at all - local current_time = os_time(); - local timeout_start = math_max(session.hibernating, session.first_hibernated_push or session.hibernating); - if session.push_identifier ~= nil and not session.first_hibernated_push then - session.log("debug", "No push happened since hibernation started, hibernating session for up to %d extra seconds", resume_timeout); - return resume_timeout; - end - if session.push_identifier ~= nil and current_time-timeout_start < resume_timeout then - session.log("debug", "A push happened since hibernation started, hibernating session for up to %d extra seconds", resume_timeout-(current_time-timeout_start)); - return resume_timeout-(current_time-timeout_start); -- time left to wait - end - session.log("debug", "Destroying session for hibernating too long"); - session_registry.set(session.username, session.resumption_token, nil); - -- save only actual h value and username/host (for security) - old_session_registry.set(session.username, session.resumption_token, { - h = session.handled_stanza_count, - username = session.username, - host = session.host - }); - session.resumption_token = nil; - sessionmanager.destroy_session(session); - else - session.log("debug", "Session resumed before hibernation timeout, all is well") - end - end); - return true; -- Postpone destruction for now - end - end -end); - -local function handle_s2s_destroyed(event) - local session = event.session; - local queue = session.outgoing_stanza_queue; - if queue and #queue > 0 then - session.log("warn", "Destroying session with %d unacked stanzas", #queue); - if s2s_resend then - for i = 1, #queue do - module:send(queue[i]); - end - session.outgoing_stanza_queue = nil; - else - handle_unacked_stanzas(session); - end - end -end - -module:hook("s2sout-destroyed", handle_s2s_destroyed); -module:hook("s2sin-destroyed", handle_s2s_destroyed); - -local function get_session_id(session) - return session.id or (tostring(session):match("[a-f0-9]+$")); -end - -function handle_resume(session, stanza, xmlns_sm) - if session.full_jid then - session.log("warn", "Tried to resume after resource binding"); - session.send(st.stanza("failed", { xmlns = xmlns_sm }) - :tag("unexpected-request", { xmlns = xmlns_errors }) - ); - return true; - end - - local id = stanza.attr.previd; - local original_session = session_registry.get(session.username, id); - if not original_session then - session.log("debug", "Tried to resume non-existent session with id %s", id); - local old_session = old_session_registry.get(session.username, id); - if old_session and session.username == old_session.username - and session.host == old_session.host - and old_session.h then - session.send(st.stanza("failed", { xmlns = xmlns_sm, h = string.format("%d", old_session.h) }) - :tag("item-not-found", { xmlns = xmlns_errors }) - ); - else - session.send(st.stanza("failed", { xmlns = xmlns_sm }) - :tag("item-not-found", { xmlns = xmlns_errors }) - ); - end; - elseif session.username == original_session.username - and session.host == original_session.host then - session.log("debug", "mod_smacks resuming existing session %s...", get_session_id(original_session)); - original_session.log("debug", "mod_smacks session resumed from %s...", get_session_id(session)); - -- TODO: All this should move to sessionmanager (e.g. session:replace(new_session)) - if original_session.conn then - original_session.log("debug", "mod_smacks closing an old connection for this session"); - local conn = original_session.conn; - c2s_sessions[conn] = nil; - conn:close(); - end - local migrated_session_log = session.log; - original_session.ip = session.ip; - original_session.conn = session.conn; - original_session.send = session.send; - original_session.close = session.close; - original_session.filter = session.filter; - original_session.filter.session = original_session; - original_session.filters = session.filters; - original_session.stream = session.stream; - original_session.secure = session.secure; - original_session.hibernating = nil; - session.log = original_session.log; - session.type = original_session.type; - wrap_session(original_session, true); - -- Inform xmppstream of the new session (passed to its callbacks) - original_session.stream:set_session(original_session); - -- Similar for connlisteners - c2s_sessions[session.conn] = original_session; - - original_session.send(st.stanza("resumed", { xmlns = xmlns_sm, - h = string.format("%d", original_session.handled_stanza_count), previd = id })); - - -- Fake an with the h of the from the client - original_session:dispatch_stanza(st.stanza("a", { xmlns = xmlns_sm, - h = stanza.attr.h })); - - -- Ok, we need to re-send any stanzas that the client didn't see - -- ...they are what is now left in the outgoing stanza queue - -- We have to use the send of "session" because we don't want to add our resent stanzas - -- to the outgoing queue again - local queue = original_session.outgoing_stanza_queue; - session.log("debug", "resending all unacked stanzas that are still queued after resume, #queue = %d", #queue); - for i=1,#queue do - session.send(queue[i]); - end - session.log("debug", "all stanzas resent, now disabling send() in this migrated session, #queue = %d", #queue); - function session.send(stanza) - migrated_session_log("error", "Tried to send stanza on old session migrated by smacks resume (maybe there is a bug?): %s", tostring(stanza)); - return false; - end - module:fire_event("smacks-hibernation-end", {origin = session, resumed = original_session, queue = queue}); - request_ack_if_needed(original_session, true, "handle_resume", nil); - else - module:log("warn", "Client %s@%s[%s] tried to resume stream for %s@%s[%s]", - session.username or "?", session.host or "?", session.type, - original_session.username or "?", original_session.host or "?", original_session.type); - session.send(st.stanza("failed", { xmlns = xmlns_sm }) - :tag("not-authorized", { xmlns = xmlns_errors })); - end - return true; -end -module:hook_stanza(xmlns_sm2, "resume", function (session, stanza) return handle_resume(session, stanza, xmlns_sm2); end); -module:hook_stanza(xmlns_sm3, "resume", function (session, stanza) return handle_resume(session, stanza, xmlns_sm3); end); - -module:hook("csi-client-active", function (event) - if event.origin.smacks then - request_ack_if_needed(event.origin, true, "csi-active", nil); - end -end); - -module:hook("csi-flushing", function(event) - local session = event.session; - if session.smacks then - if not session.awaiting_ack and not session.hibernating and not session.destroyed then - session.log("debug", "Sending (csi-flushing)"); - session.awaiting_ack = true; -- The send() call may invoke this event again, so set this first - (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })) - end - end -end); - -local function handle_read_timeout(event) - local session = event.session; - if session.smacks then - if session.awaiting_ack then - if session.awaiting_ack_timer then - session.awaiting_ack_timer:stop(); - end - if session.delayed_ack_timer then - session.delayed_ack_timer:stop(); - session.delayed_ack_timer = nil; - end - return false; -- Kick the session - end - session.log("debug", "Sending (read timeout)"); - (session.sends2s or session.send)(st.stanza("r", { xmlns = session.smacks })); - session.awaiting_ack = true; - if not session.delayed_ack_timer then - session.delayed_ack_timer = stoppable_timer(delayed_ack_timeout, function() - delayed_ack_function(session, nil); - end); - end - return true; - end -end - -module:hook("s2s-read-timeout", handle_read_timeout); -module:hook("c2s-read-timeout", handle_read_timeout); diff --git a/plugins/mod_throttle_presence/README.markdown b/plugins/mod_throttle_presence/README.markdown deleted file mode 100644 index c953ad6..0000000 --- a/plugins/mod_throttle_presence/README.markdown +++ /dev/null @@ -1,31 +0,0 @@ ---- -labels: -- 'Stage-Beta' -summary: Limit presence stanzas to save traffic -... - -Introduction -============ - -For most people 'presence' (status changes) of contacts make up most of -the traffic received by their client. However much of the time it is not -essential to have highly accurate presence information. - -This module automatically cuts down on presence traffic when clients -indicate they are inactive (using the [CSI protocol](mod_csi.html)). - -This is extremely valuable for mobile clients that wish to save battery -power while in the background. - -Configuration -============= - -Just load the module (e.g. in modules\_enabled). There are no -configuration options. - -Compatibility -============= - - ----- ------- - 0.9 Works - ----- ------- diff --git a/plugins/mod_throttle_presence/mod_throttle_presence.lua b/plugins/mod_throttle_presence/mod_throttle_presence.lua deleted file mode 100644 index 9792391..0000000 --- a/plugins/mod_throttle_presence/mod_throttle_presence.lua +++ /dev/null @@ -1,53 +0,0 @@ -local filters = require "util.filters"; -local st = require "util.stanza"; - -module:depends("csi"); - -local function presence_filter(stanza, session) - if getmetatable(stanza) ~= st.stanza_mt then - return stanza; -- Things we don't want to touch - end - if stanza._flush then - stanza._flush = nil; - return stanza; - end - local buffer = session.presence_buffer; - local from = stanza.attr.from; - if stanza.name == "presence" and (stanza.attr.type == nil or stanza.attr.type == "unavailable") then - module:log("debug", "Buffering presence stanza from %s to %s", stanza.attr.from, session.full_jid); - buffer[stanza.attr.from] = st.clone(stanza); - return nil; -- Drop this stanza (we've stored it for later) - else - local cached_presence = buffer[stanza.attr.from]; - if cached_presence then - module:log("debug", "Important stanza for %s from %s, flushing presence", session.full_jid, from); - stanza._flush = true; - cached_presence._flush = true; - session.send(cached_presence); - buffer[stanza.attr.from] = nil; - end - end - return stanza; -end - -local function throttle_session(event) - local session = event.origin; - if session.presence_buffer then return; end - module:log("debug", "Suppressing presence updates to %s", session.full_jid); - session.presence_buffer = {}; - filters.add_filter(session, "stanzas/out", presence_filter); -end - -local function restore_session(event) - local session = event.origin; - if not session.presence_buffer then return; end - filters.remove_filter(session, "stanzas/out", presence_filter); - module:log("debug", "Flushing buffer for %s", session.full_jid); - for jid, presence in pairs(session.presence_buffer) do - session.send(presence); - end - session.presence_buffer = nil; -end - -module:hook("csi-client-inactive", throttle_session); -module:hook("csi-client-active", restore_session); diff --git a/prosody-modules.list b/prosody-modules.list deleted file mode 100644 index fc12045..0000000 --- a/prosody-modules.list +++ /dev/null @@ -1,9 +0,0 @@ -mod_auth_sql -mod_blocking -mod_carbons_adhoc -mod_carbons_copies -mod_filter_chatstates -mod_limit_auth -mod_log_auth -mod_smacks -mod_throttle_presence diff --git a/prosody-modules.revision b/prosody-modules.revision deleted file mode 100644 index 378bfa8..0000000 --- a/prosody-modules.revision +++ /dev/null @@ -1 +0,0 @@ -ecfd7aece33b diff --git a/t/Dockerfile b/t/Dockerfile deleted file mode 100644 index 64765de..0000000 --- a/t/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -# DOCKER_NAME=prosody-bookworm -FROM docker.mgm.sipwise.com/sipwise-bookworm:latest - -# Important! Update this no-op ENV variable when this Dockerfile -# is updated with the current date. It will force refresh of all -# of the base images and things like `apt-get update` won't be using -# old cached versions when the Dockerfile is built. -ENV REFRESHED_AT 2023-06-26 - -RUN apt-get update && apt-get install --assume-yes lua-check - -RUN echo './t/testrunner' >>/root/.bash_history - -WORKDIR /code/ - -################################################################################ -# Instructions for usage -# ---------------------- -# When you want to build the base image from scratch -# jump to the next section if you don't want to build yourself!: -# -# % docker build --tag="prosody-bookworm" -f t/Dockerfile . -# % docker run --rm -i -t -v $(pwd):/code:rw prosody-bookworm:latest bash -# -# Use the existing docker image: -# % docker pull docker.mgm.sipwise.com/prosody-bookworm -# NOTE: run the following command from root folder of git repository: -# % docker run --rm -i -t -v $(pwd):/code:rw docker.mgm.sipwise.com/prosody-bookworm:latest bash -# -# Inside docker (the command is in history, just press UP button): -# ./t/testrunner -# -################################################################################ diff --git a/t/testrunner b/t/testrunner deleted file mode 100755 index 44061f5..0000000 --- a/t/testrunner +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -set -e -set -u - -if [ -d /results ] ; then - # Running from Jenkins (RW) - RESULTS="/results" -else - # Running locally in Docker - RESULTS="./results" - mkdir -p "${RESULTS}" -fi - -luacheck --formatter JUnit core plugins util > ${RESULTS}/prosody.luacheck diff --git a/update_plugins.sh b/update_plugins.sh deleted file mode 100755 index 8b5b6b8..0000000 --- a/update_plugins.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -# -set -e - -MOD_SRC=$1 - -usage() { - echo "$0 modules_src_dir" - printf "\tmodules_src_dir:\tpath to prosody-modules mercurial source\n" -} - -refresh_sources() { - echo "refresh sources at $MOD_SRC" - ( cd "$MOD_SRC" && hg pull && hg update ) -} - -copy_modules() { - while read -r dir ; do - if [ -d "$MOD_SRC/$dir" ] ; then - cp -vr "$MOD_SRC/$dir" plugins - else - echo "$MOD_SRC/$dir no longer there" - fi - done < prosody-modules.list -} - -get_revision_id() { - (cd "$MOD_SRC/$dir" && hg id -i) > 'prosody-modules.revision' -} - -if [ $# -ne 1 ] ; then - echo "wrong number of parameters" >&2 - usage - exit 1 -fi - -if ! [ -d "$MOD_SRC" ] ; then - printf "modules_src_dir[%s] not found\n" "$MOD_SRC" -fi - -refresh_sources -copy_modules -get_revision_id -exit 0 diff --git a/util/prosody_sipwise_migrator b/util/prosody_sipwise_migrator deleted file mode 100755 index a612b70..0000000 --- a/util/prosody_sipwise_migrator +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env lua5.2 - -local CFG_SOURCEDIR='/usr/lib/prosody'; -local CFG_CONFIGDIR='/etc/prosody'; - -local mam_query =[[ -select `id`, `username`,UuidFromBin(`key`),`stanza`,`epoch`,`with` -from sipwise_mam as mam -where UuidFromBin(`key`) not in (select `key` from prosodyarchive) -order by username, id asc; -]] - -local mam_del =[[ -delete from sipwise_mam where id = ?; -]] - -local archive_insert =[[ -insert into `prosodyarchive` (`host`,`user`,`store`,`key`,`when`,`with`,`type`,`value`) -values(?,?,'archive',?,?,?,'xml',?); -]] - -local offline_query =[[ -select `id`, `domain`, `username`, `stanza` -from sipwise_offline -order by username, id asc; -]] - -local offline_del = [[ -delete from sipwise_offline where id = ?; -]] - -local offline_insert =[[ -insert into `prosodyarchive` (`host`,`user`,`store`,`key`,`when`,`with`,`type`,`value`) -values(?,?,'offline',?,?,'','xml',?); -]] - -local prosodyarchive_count =[[ -select count(sort_id) from prosodyarchive; -]] - -local function is_relative(path) - local path_sep = package.config:sub(1,1); - return ((path_sep == "/" and path:sub(1,1) ~= "/") - or (path_sep == "\\" and (path:sub(1,1) ~= "/" and path:sub(2,3) ~= ":\\"))) -end - --- Tell Lua where to find our libraries -if CFG_SOURCEDIR then - local function filter_relative_paths(path) - if is_relative(path) then return ""; end - end - local function sanitise_paths(paths) - return (paths:gsub("[^;]+;?", filter_relative_paths):gsub(";;+", ";")); - end - package.path = sanitise_paths(CFG_SOURCEDIR.."/?.lua;"..package.path); - package.cpath = sanitise_paths(CFG_SOURCEDIR.."/?.so;"..package.cpath); -end - -local configmanager = require "core.configmanager"; -local ok, _, err = configmanager.load(CFG_CONFIGDIR.."/prosody.cfg.lua", "lua") - -if not ok then - print("Error: can't load the config file."..err); - os.exit(1); -end - -local sql_config = configmanager.get("*", "sql"); - -if not sql_config then - print("Error: sql not found in the config file."); - os.exit(1); -end - -local deserialize = require "util.serialization".deserialize; -local st = require "util.stanza"; -local sql = require "util.sql"; -local jid_split = require "util.jid".split; -local uuid = require "util.uuid".generate; -local timestamp_parse = require "util.datetime".parse; - -local engine = sql:create_engine(sql_config); -engine:connect(); - --- from mod_storage_sql.lua of prosody 0.11.3 -local function create_table() - local Table, Column, Index = sql.Table, sql.Column, sql.Index; - - local ProsodyArchiveTable = Table { - name="prosodyarchive"; - Column { name="sort_id", type="INTEGER", primary_key=true, auto_increment=true }; - Column { name="host", type="TEXT", nullable=false }; - Column { name="user", type="TEXT", nullable=false }; - Column { name="store", type="TEXT", nullable=false }; - Column { name="key", type="TEXT", nullable=false }; -- item id - Column { name="when", type="INTEGER", nullable=false }; -- timestamp - Column { name="with", type="TEXT", nullable=false }; -- related id - Column { name="type", type="TEXT", nullable=false }; - Column { name="value", type="MEDIUMTEXT", nullable=false }; - Index { name="prosodyarchive_index", unique = engine.params.driver ~= "MySQL", "host", "user", "store", "key" }; - Index { name="prosodyarchive_with_when", "host", "user", "store", "with", "when" }; - Index { name="prosodyarchive_when", "host", "user", "store", "when" }; - }; - engine:transaction(function() - ProsodyArchiveTable:create(engine); - end); -end - -local function check_prosodyarchive() - for row in engine:select(prosodyarchive_count) do --luacheck: ignore - return row[1] - end -end - -local function migrate_mam() - local i = 0 - for row in engine:select(mam_query) do - local user, host, _ = jid_split(row[2]); - -- print("id:"..row[1].." username:"..row[2].." uuid:"..row[3]); - local stanza = st.deserialize(deserialize(row[4])); - -- print("stanza:"..tostring(stanza)); - engine:insert(archive_insert, host, user, row[3], row[5], row[6], tostring(stanza)); - engine:delete(mam_del, row[1]); - i = i + 1; - end - if i > 0 then - engine.conn:commit(); - print("migrated "..i.." mam messages"); - end -end - -local function migrate_offline() - local i = 0 - for row in engine:select(offline_query) do - -- print("id:"..row[1].." username:"..row[3].." domain:"..row[2]); - local stanza = st.deserialize(deserialize(row[4])); - local when = timestamp_parse(stanza.attr.stamp) - stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil; - engine:insert(offline_insert, row[2], row[3], uuid(), when, tostring(stanza)); - engine:delete(offline_del, row[1]); - i = i + 1; - end - if i > 0 then - engine.conn:commit(); - print("migrated "..i.." offline messages"); - end -end - -if arg[1] == '--create' then - if pcall(check_prosodyarchive) then - print("prosodyarchive already there"); - else - create_table(); - if check_prosodyarchive() then - print("prosodyarchive created"); - end - end -else - migrate_mam(); - migrate_offline(); -end