From 9eca69d092897f8a7724698c78b787fb8021ab80 Mon Sep 17 00:00:00 2001 From: Christophe Romain Date: Thu, 30 Apr 2015 09:02:06 +0200 Subject: [PATCH] Remove modules included in ejabberd 15.04 --- mod_admin_extra/COPYING | 343 ----- mod_admin_extra/ChangeLog | 117 -- mod_admin_extra/README.txt | 83 -- mod_admin_extra/conf/mod_admin_extra.yml | 23 - mod_admin_extra/mod_admin_extra.spec | 5 - mod_admin_extra/src/mod_admin_extra.erl | 1583 ---------------------- mod_admin_extra/src/mod_ecomm_test.erl | 426 ------ mod_muc_admin/COPYING | 343 ----- mod_muc_admin/ChangeLog | 80 -- mod_muc_admin/README.txt | 43 - mod_muc_admin/conf/mod_muc_admin.yml | 2 - mod_muc_admin/mod_muc_admin.spec | 5 - mod_muc_admin/src/mod_muc_admin.erl | 876 ------------ 13 files changed, 3929 deletions(-) delete mode 100644 mod_admin_extra/COPYING delete mode 100644 mod_admin_extra/ChangeLog delete mode 100644 mod_admin_extra/README.txt delete mode 100644 mod_admin_extra/conf/mod_admin_extra.yml delete mode 100644 mod_admin_extra/mod_admin_extra.spec delete mode 100644 mod_admin_extra/src/mod_admin_extra.erl delete mode 100644 mod_admin_extra/src/mod_ecomm_test.erl delete mode 100644 mod_muc_admin/COPYING delete mode 100644 mod_muc_admin/ChangeLog delete mode 100644 mod_muc_admin/README.txt delete mode 100644 mod_muc_admin/conf/mod_muc_admin.yml delete mode 100644 mod_muc_admin/mod_muc_admin.spec delete mode 100644 mod_muc_admin/src/mod_muc_admin.erl diff --git a/mod_admin_extra/COPYING b/mod_admin_extra/COPYING deleted file mode 100644 index e21e8c4..0000000 --- a/mod_admin_extra/COPYING +++ /dev/null @@ -1,343 +0,0 @@ -As a special exception, the authors give permission to link this program -with the OpenSSL library and distribute the resulting binary. - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/mod_admin_extra/ChangeLog b/mod_admin_extra/ChangeLog deleted file mode 100644 index 0049160..0000000 --- a/mod_admin_extra/ChangeLog +++ /dev/null @@ -1,117 +0,0 @@ -2009-06-15 Badlop - - * src/mod_admin_extra.erl: Added command to check the password by - providing a MD5 or SHA hash. - -2009-02-16 Badlop - - * src/mod_admin_extra.erl: Fix srg_user_add arguments - -2009-02-09 Badlop - - * src/mod_admin_extra.erl: Calculation of 'stats registeredusers' - works also with non-internal authentication methods (thanks to - Francois de Metz)(EJAB-864) - -2009-01-27 Badlop - - * README.txt: Explicitely mention that this module does not work - with any ejabberd 2.0.x or older - - * src/mod_admin_extra.erl: In the srg_create command, allow to - separate group identifiers in the Display argument with escaped - newline character. Explain this possibility in the command long - description. - -2008-11-10 Badlop - - * src/mod_admin_extra.erl: Renamed command send_message to - send_message_headline. New command send_message_chat. (thanks to - Xyu) - -2008-10-31 Badlop - - * src/mod_admin_extra.erl: Deleted the duplicated command - delete_older_messages (EJAB-814). Rename the other delete_older_* - commands. - -2008-10-12 Badlop - - * README.txt: It requires ejabberd trunk SVN 1635 or newer - - * src/mod_admin_extra.erl: Renamed mod_ctlextra to - mod_admin_extra, as it now implements ejabberd commands instead of - ejabberdctl commands - -2008-04-26 Badlop - - * src/mod_ctlextra.erl: New command: ban-account - * README.txt: Documented new command - -2008-04-04 Badlop - - * src/mod_ctlextra.erl: Added new command - rosteritem-purge [options] - -2008-03-19 Badlop - - * src/mod_ctlextra.erl: Added two new commands for administration - of Shared Roster Groups: "srg-list-groups host" and "srg-get-info - group host" (thanks to Taylor Laramie) - -2008-03-09 Badlop - - * src/mod_ctlextra.erl: Show the result of each table export - -2008-03-04 Badlop - - * src/mod_ctlextra.erl: New command 'stats - onlineusersnode'. Removed old unusued code. - - * README.txt: Updated module page - -2008-01-20 Badlop - - * src/mod_ctlextra.erl: Allow to define group name with spaces - * README.txt: Likewise - -2007-11-14 Badlop - - * src/mod_ctlextra.erl: Updated to ejabberd SVN. - -2007-09-08 Badlop - - * src/mod_ctlextra.erl: Bugfix: unregister commands when module - stops. Removed all MUC-related commands. - -2007-08-29 Badlop - - * src/mod_ctlextra.erl: Added command: stats uptime-seconds. - -2007-08-24 Badlop - - * src/mod_ctlextra.erl: Fixed bug in vcard-set command that - forgot second level attributes. - -2007-08-23 Badlop - - * src/mod_ctlextra.erl: Command add-rosteritem now pushes the - roster item to the client. New command rem-rosteritem. - -2007-08-19 Badlop - - * src/mod_ctlextra.erl: Now vcard-get and vcard-set are more - compatible with mod_vcard_odbc and mod_vcard_ldap. - -2007-08-16 Badlop - - * src/mod_ctlextra.erl: add-rosteritem only adds an item in a - roster. - -2007-08-07 Badlop - - * src/mod_ctlextra.erl: Fixed indentation. - - * ChangeLog: New file to track changes. - - * README.txt: Removed Changelog section. diff --git a/mod_admin_extra/README.txt b/mod_admin_extra/README.txt deleted file mode 100644 index bb9d107..0000000 --- a/mod_admin_extra/README.txt +++ /dev/null @@ -1,83 +0,0 @@ - - - mod_admin_extra - Additional ejabberd commands - - NOTE: This module is included in ejabberd since 15.04 - - Author: Badlop - Homepage: http://www.ejabberd.im/mod_admin_extra - - - CONFIGURATION - ============= - -Add the module to your ejabberd.yml, on the modules section: -modules: - mod_admin_extra: {} - -The configurable options are: -- module_resource: - Indicate the resource that the XMPP stanzas must use in the FROM or TO JIDs. - This is only useful in the vcard set and get commands. - The default value is "mod_admin_extra". - -In this example configuration, the users vcards can only be modified -by executing mod_admin_extra commands. -Notice that this needs the patch - https://support.process-one.net/browse/EJAB-797 -acl: - adminextraresource: - resource: "modadminextraf8x,31ad" -access: - vcard_set: - adminextraresource: allow - all: deny -modules: - mod_admin_extra: - module_resource: "modadminextraf8x,31ad" - mod_vcard: - access_set: vcard_set - - - USAGE - ===== - -Now you have several new commands in ejabberdctl. - -Description of some commands: - - - vcard-* - Example: ejabberdctl vcard-get joe myjab.net email - - - pushroster* - The file used by 'pushroster' and 'pushroster-all' must be placed: - - Windows: on the directory were you installed ejabberd: - 'C:/Program Files/ejabberd' - - Other OS: on the same directory where the .beam files are. - Example content for the roster file: - [{<<"bob">>, <<"example.org">>, <<"workers">>, <<"Bob">>}, - {<<"mart">>, <<"example.org">>, <<"workers">>, <<"Mart">>}, - {<<"Rich">>, <<"example.org">>, <<"bosses">>, <<"Rich">>}]. - - - srg-create - If you want to put a group Name with blankspaces, use the characters - "' and '" to define when the Name starts and ends. - For example: - ejabberdctl srg-create g1 example.org "'Group number 1'" this_is_g1 g1 - - - ban-account - - This command kicks all the connected sessions of the account from the - server. It also changes his password to another randomly - generated, so he can't login anymore unless a server administrator - changes him again the password. - - It is possible to define the reason of the ban. The new password - also includes the reason and the date and time of the ban. - - For example, if this command is called: - ejabberdctl vhost example.org ban-account boby Spammed several MUC rooms - then the sessions of the local account which JID is boby@example.org - will be kicked, and its password will be set to something like this: - BANNED_ACCOUNT--20080425T21:45:07--2176635--Spammed_several_MUC_rooms - diff --git a/mod_admin_extra/conf/mod_admin_extra.yml b/mod_admin_extra/conf/mod_admin_extra.yml deleted file mode 100644 index c568a70..0000000 --- a/mod_admin_extra/conf/mod_admin_extra.yml +++ /dev/null @@ -1,23 +0,0 @@ -# The configurable options are: -# - module_resource: -# Indicate the resource that the XMPP stanzas must use in the FROM or TO JIDs. -# This is only useful in the vcard set and get commands. -# The default value is "mod_admin_extra". -# -# In this example configuration, the users vcards can only be modified -# by executing mod_admin_extra commands. - -acl: - adminextraresource: - - "resource": "modadminextraf8x,31ad" - -access: - vcard_set: - adminextraresource: allow - all: deny - -modules: - mod_admin_extra: - - "module_resource": "modadminextraf8x,31ad" - mod_vcard: - - "access_set": "vcard_set" diff --git a/mod_admin_extra/mod_admin_extra.spec b/mod_admin_extra/mod_admin_extra.spec deleted file mode 100644 index a4c575d..0000000 --- a/mod_admin_extra/mod_admin_extra.spec +++ /dev/null @@ -1,5 +0,0 @@ -author: "Badlop " -category: "admin" -summary: "Additional ejabberd commands" -home: "https://github.com/processone/mod_admin_extra" -url: "git@github.com:processone/mod_admin_extra.git" diff --git a/mod_admin_extra/src/mod_admin_extra.erl b/mod_admin_extra/src/mod_admin_extra.erl deleted file mode 100644 index 043b6f3..0000000 --- a/mod_admin_extra/src/mod_admin_extra.erl +++ /dev/null @@ -1,1583 +0,0 @@ -%%%------------------------------------------------------------------- -%%% File : mod_admin_extra.erl -%%% Author : Badlop -%%% Purpose : Contributed administrative functions and commands -%%% Created : 10 Aug 2008 by Badlop -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%------------------------------------------------------------------- - --module(mod_admin_extra). --author('badlop@process-one.net'). - --behaviour(gen_mod). - --include("logger.hrl"). - --export([start/2, stop/1, - %% Node - compile/1, - load_config/1, - get_cookie/0, - remove_node/1, - export2odbc/2, - %% Accounts - set_password/3, - check_password_hash/4, - delete_old_users/1, - delete_old_users_vhost/2, - ban_account/3, - num_active_users/2, - %% Sessions - num_resources/2, - resource_num/3, - kick_session/4, - status_num/2, status_num/1, - status_list/2, status_list/1, - connected_users_info/0, - connected_users_vhost/1, - set_presence/7, - user_sessions_info/2, - %% Vcard - set_nickname/3, - get_vcard/3, - get_vcard/4, - get_vcard_multi/4, - set_vcard/4, - set_vcard/5, - %% Roster - add_rosteritem/7, - delete_rosteritem/4, - process_rosteritems/5, - get_roster/2, - push_roster/3, - push_roster_all/1, - push_alltoall/2, - %% mod_last - get_last/2, - set_last/4, - %% mod_private - private_get/4, - private_set/3, - %% mod_shared_roster - srg_create/5, - srg_delete/2, - srg_list/1, - srg_get_info/2, - srg_get_members/2, - srg_user_add/4, - srg_user_del/4, - %% Stanza - send_message/5, - send_stanza_c2s/4, - privacy_set/3, - %% Stats - stats/1, stats/2 - ]). - --include("ejabberd.hrl"). --include("ejabberd_commands.hrl"). --include("mod_roster.hrl"). --include("jlib.hrl"). - -%% Copied from ejabberd_sm.erl --record(session, {sid, usr, us, priority, info}). - - -%%% -%%% gen_mod -%%% - -start(_Host, _Opts) -> - ejabberd_commands:register_commands(commands()). - -stop(_Host) -> - ejabberd_commands:unregister_commands(commands()). - - -%%% -%%% Register commands -%%% - -commands() -> - Vcard1FieldsString = "Some vcard field names in get/set_vcard are:\n" - " FN - Full Name\n" - " NICKNAME - Nickname\n" - " BDAY - Birthday\n" - " TITLE - Work: Position\n" - " ROLE - Work: Role", - - Vcard2FieldsString = "Some vcard field names and subnames in get/set_vcard2 are:\n" - " N FAMILY - Family name\n" - " N GIVEN - Given name\n" - " N MIDDLE - Middle name\n" - " ADR CTRY - Address: Country\n" - " ADR LOCALITY - Address: City\n" - " TEL HOME - Telephone: Home\n" - " TEL CELL - Telephone: Cellphone\n" - " TEL WORK - Telephone: Work\n" - " TEL VOICE - Telephone: Voice\n" - " EMAIL USERID - E-Mail Address\n" - " ORG ORGNAME - Work: Company\n" - " ORG ORGUNIT - Work: Department", - - VcardXEP = "For a full list of vCard fields check XEP-0054: vcard-temp at " - "http://www.xmpp.org/extensions/xep-0054.html", - - [ - #ejabberd_commands{name = compile, tags = [erlang], - desc = "Recompile and reload Erlang source code file", - module = ?MODULE, function = compile, - args = [{file, string}], - result = {res, rescode}}, - #ejabberd_commands{name = load_config, tags = [server], - desc = "Load ejabberd configuration file", - module = ?MODULE, function = load_config, - args = [{file, string}], - result = {res, rescode}}, - #ejabberd_commands{name = get_cookie, tags = [erlang], - desc = "Get the Erlang cookie of this node", - module = ?MODULE, function = get_cookie, - args = [], - result = {cookie, string}}, - #ejabberd_commands{name = remove_node, tags = [erlang], - desc = "Remove an ejabberd node from Mnesia clustering config", - module = ?MODULE, function = remove_node, - args = [{node, string}], - result = {res, rescode}}, - #ejabberd_commands{name = export2odbc, tags = [mnesia], %% Copied to ejabberd 2.1.x after 11 - desc = "Export Mnesia tables to files in directory", - module = ?MODULE, function = export2odbc, - args = [{host, string}, {path, string}], - result = {res, rescode}}, - - #ejabberd_commands{name = num_active_users, tags = [accounts, stats], - desc = "Get number of users active in the last days", - module = ?MODULE, function = num_active_users, - args = [{host, binary}, {days, integer}], - result = {users, integer}}, - #ejabberd_commands{name = delete_old_users, tags = [accounts, purge], - desc = "Delete users that didn't log in last days, or that never logged", - module = ?MODULE, function = delete_old_users, - args = [{days, integer}], - result = {res, restuple}}, - #ejabberd_commands{name = delete_old_users_vhost, tags = [accounts, purge], - desc = "Delete users that didn't log in last days in vhost, or that never logged", - module = ?MODULE, function = delete_old_users_vhost, - args = [{host, binary}, {days, integer}], - result = {res, restuple}}, - - #ejabberd_commands{name = check_account, tags = [accounts], - desc = "Check if an account exists or not", - module = ejabberd_auth, function = is_user_exists, - args = [{user, binary}, {host, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = check_password, tags = [accounts], - desc = "Check if a password is correct", - module = ejabberd_auth, function = check_password, - args = [{user, binary}, {host, binary}, {password, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = check_password_hash, tags = [accounts], - desc = "Check if the password hash is correct", - longdesc = "Allowed hash methods: md5, sha.", - module = ?MODULE, function = check_password_hash, - args = [{user, binary}, {host, binary}, {passwordhash, binary}, {hashmethod, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = change_password, tags = [accounts], - desc = "Change the password of an account", - module = ?MODULE, function = set_password, - args = [{user, binary}, {host, binary}, {newpass, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = ban_account, tags = [accounts], - desc = "Ban an account: kick sessions and set random password", - module = ?MODULE, function = ban_account, - args = [{user, binary}, {host, binary}, {reason, binary}], - result = {res, rescode}}, - - #ejabberd_commands{name = num_resources, tags = [session], - desc = "Get the number of resources of a user", - module = ?MODULE, function = num_resources, - args = [{user, binary}, {host, binary}], - result = {resources, integer}}, - #ejabberd_commands{name = resource_num, tags = [session], - desc = "Resource string of a session number", - module = ?MODULE, function = resource_num, - args = [{user, binary}, {host, binary}, {num, integer}], - result = {resource, string}}, - #ejabberd_commands{name = kick_session, tags = [session], - desc = "Kick a user session", - module = ?MODULE, function = kick_session, - args = [{user, binary}, {host, binary}, {resource, binary}, {reason, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = status_num_host, tags = [session, stats], - desc = "Number of logged users with this status in host", - module = ?MODULE, function = status_num, - args = [{host, binary}, {status, binary}], - result = {users, integer}}, - #ejabberd_commands{name = status_num, tags = [session, stats], - desc = "Number of logged users with this status", - module = ?MODULE, function = status_num, - args = [{status, binary}], - result = {users, integer}}, - #ejabberd_commands{name = status_list_host, tags = [session], - desc = "List of users logged in host with their statuses", - module = ?MODULE, function = status_list, - args = [{host, binary}, {status, binary}], - result = {users, {list, - {userstatus, {tuple, [ - {user, string}, - {host, string}, - {resource, string}, - {priority, integer}, - {status, string} - ]}} - }}}, - #ejabberd_commands{name = status_list, tags = [session], - desc = "List of logged users with this status", - module = ?MODULE, function = status_list, - args = [{status, binary}], - result = {users, {list, - {userstatus, {tuple, [ - {user, string}, - {host, string}, - {resource, string}, - {priority, integer}, - {status, string} - ]}} - }}}, - #ejabberd_commands{name = connected_users_info, - tags = [session], - desc = "List all established sessions and their information", - module = ?MODULE, function = connected_users_info, - args = [], - result = {connected_users_info, - {list, - {sessions, {tuple, - [{jid, string}, - {connection, string}, - {ip, string}, - {port, integer}, - {priority, integer}, - {node, string}, - {uptime, integer} - ]}} - }}}, - #ejabberd_commands{name = connected_users_vhost, - tags = [session], - desc = "Get the list of established sessions in a vhost", - module = ?MODULE, function = connected_users_vhost, - args = [{host, string}], - result = {connected_users_vhost, {list, {sessions, string}}}}, - #ejabberd_commands{name = user_sessions_info, - tags = [session], - desc = "Get information about all sessions of a user", - module = ?MODULE, function = user_sessions_info, - args = [{user, binary}, {host, binary}], - result = {sessions_info, - {list, - {session, {tuple, - [{connection, string}, - {ip, string}, - {port, integer}, - {priority, integer}, - {node, string}, - {uptime, integer}, - {status, string}, - {resource, string}, - {statustext, string} - ]}} - }}}, - - #ejabberd_commands{name = set_presence, - tags = [session], - desc = "Set presence of a session", - module = ?MODULE, function = set_presence, - args = [{user, binary}, {host, binary}, - {resource, binary}, {type, binary}, - {show, binary}, {status, binary}, - {priority, binary}], - result = {res, rescode}}, - - #ejabberd_commands{name = set_nickname, tags = [vcard], - desc = "Set nickname in a user's vCard", - module = ?MODULE, function = set_nickname, - args = [{user, binary}, {host, binary}, {nickname, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = get_vcard, tags = [vcard], - desc = "Get content from a vCard field", - longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n" ++ VcardXEP, - module = ?MODULE, function = get_vcard, - args = [{user, binary}, {host, binary}, {name, binary}], - result = {content, string}}, - #ejabberd_commands{name = get_vcard2, tags = [vcard], - desc = "Get content from a vCard field", - longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, - module = ?MODULE, function = get_vcard, - args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}], - result = {content, string}}, - #ejabberd_commands{name = get_vcard2_multi, tags = [vcard], - desc = "Get multiple contents from a vCard field", - longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, - module = ?MODULE, function = get_vcard_multi, - args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}], - result = {contents, {list, {value, string}}}}, - - #ejabberd_commands{name = set_vcard, tags = [vcard], - desc = "Set content in a vCard field", - longdesc = Vcard1FieldsString ++ "\n" ++ Vcard2FieldsString ++ "\n\n" ++ VcardXEP, - module = ?MODULE, function = set_vcard, - args = [{user, binary}, {host, binary}, {name, binary}, {content, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = set_vcard2, tags = [vcard], - desc = "Set content in a vCard subfield", - longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, - module = ?MODULE, function = set_vcard, - args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}, {content, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = set_vcard2_multi, tags = [vcard], - desc = "Set multiple contents in a vCard subfield", - longdesc = Vcard2FieldsString ++ "\n\n" ++ Vcard1FieldsString ++ "\n" ++ VcardXEP, - module = ?MODULE, function = set_vcard, - args = [{user, binary}, {host, binary}, {name, binary}, {subname, binary}, {contents, {list, binary}}], - result = {res, rescode}}, - - #ejabberd_commands{name = add_rosteritem, tags = [roster], - desc = "Add an item to a user's roster (supports ODBC)", - module = ?MODULE, function = add_rosteritem, - args = [{localuser, binary}, {localserver, binary}, - {user, binary}, {server, binary}, - {nick, binary}, {group, binary}, - {subs, binary}], - result = {res, rescode}}, - %%{"", "subs= none, from, to or both"}, - %%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"}, - %%{"", "will add mike@server.com to peter@localhost roster"}, - #ejabberd_commands{name = delete_rosteritem, tags = [roster], - desc = "Delete an item from a user's roster (supports ODBC)", - module = ?MODULE, function = delete_rosteritem, - args = [{localuser, binary}, {localserver, binary}, - {user, binary}, {server, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = process_rosteritems, tags = [roster], - desc = "List or delete rosteritems that match filtering options", - longdesc = "Explanation of each argument:\n" - " - action: what to do with each rosteritem that " - "matches all the filtering options\n" - " - subs: subscription type\n" - " - asks: pending subscription\n" - " - users: the JIDs of the local user\n" - " - contacts: the JIDs of the contact in the roster\n" - "\n" - "Allowed values in the arguments:\n" - " ACTION = list | delete\n" - " SUBS = SUB[:SUB]* | any\n" - " SUB = none | from | to | both\n" - " ASKS = ASK[:ASK]* | any\n" - " ASK = none | out | in\n" - " USERS = JID[:JID]* | any\n" - " CONTACTS = JID[:JID]* | any\n" - " JID = characters valid in a JID, and can use the " - "globs: *, ?, ! and [...]\n" - "\n" - "This example will list roster items with subscription " - "'none', 'from' or 'to' that have any ask property, of " - "local users which JID is in the virtual host " - "'example.org' and that the contact JID is either a " - "bare server name (without user part) or that has a " - "user part and the server part contains the word 'icq'" - ":\n list none:from:to any *@example.org *:*@*icq*", - module = ?MODULE, function = process_rosteritems, - args = [{action, string}, {subs, string}, - {asks, string}, {users, string}, - {contacts, string}], - result = {response, - {list, - {pairs, {tuple, - [{user, string}, - {contact, string} - ]}} - }}}, - #ejabberd_commands{name = get_roster, tags = [roster], - desc = "Get roster of a local user", - module = ?MODULE, function = get_roster, - args = [{user, binary}, {host, binary}], - result = {contacts, {list, {contact, {tuple, [ - {jid, string}, - {nick, string}, - {subscription, string}, - {ask, string}, - {group, string} - ]}}}}}, - #ejabberd_commands{name = push_roster, tags = [roster], - desc = "Push template roster from file to a user", - module = ?MODULE, function = push_roster, - args = [{file, string}, {user, string}, {host, string}], - result = {res, rescode}}, - #ejabberd_commands{name = push_roster_all, tags = [roster], - desc = "Push template roster from file to all those users", - module = ?MODULE, function = push_roster_all, - args = [{file, string}], - result = {res, rescode}}, - #ejabberd_commands{name = push_alltoall, tags = [roster], - desc = "Add all the users to all the users of Host in Group", - module = ?MODULE, function = push_alltoall, - args = [{host, string}, {group, string}], - result = {res, rescode}}, - - #ejabberd_commands{name = get_last, tags = [last], - desc = "Get last activity information", - longdesc = "Timestamp is the seconds since" - "1970-01-01 00:00:00 UTC, for example: date +%s", - module = ?MODULE, function = get_last, - args = [{user, binary}, {host, binary}], - result = {last_activity, string}}, - #ejabberd_commands{name = set_last, tags = [last], - desc = "Set last activity information", - longdesc = "Timestamp is the seconds since" - "1970-01-01 00:00:00 UTC, for example: date +%s", - module = ?MODULE, function = set_last, - args = [{user, string}, {host, string}, {timestamp, integer}, {status, string}], - result = {res, rescode}}, - - #ejabberd_commands{name = private_get, tags = [private], - desc = "Get some information from a user private storage", - module = ?MODULE, function = private_get, - args = [{user, binary}, {host, binary}, {element, binary}, {ns, binary}], - result = {res, string}}, - #ejabberd_commands{name = private_set, tags = [private], - desc = "Set to the user private storage", - module = ?MODULE, function = private_set, - args = [{user, binary}, {host, binary}, {element, binary}], - result = {res, rescode}}, - - #ejabberd_commands{name = srg_create, tags = [shared_roster_group], - desc = "Create a Shared Roster Group", - longdesc = "If you want to specify several group " - "identifiers in the Display argument,\n" - "put \\ \" around the argument and\nseparate the " - "identifiers with \\ \\ n\n" - "For example:\n" - " ejabberdctl srg_create group3 localhost " - "name desc \\\"group1\\\\ngroup2\\\"", - module = ?MODULE, function = srg_create, - args = [{group, binary}, {host, binary}, - {name, binary}, {description, binary}, {display, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = srg_delete, tags = [shared_roster_group], - desc = "Delete a Shared Roster Group", - module = ?MODULE, function = srg_delete, - args = [{group, binary}, {host, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = srg_list, tags = [shared_roster_group], - desc = "List the Shared Roster Groups in Host", - module = ?MODULE, function = srg_list, - args = [{host, binary}], - result = {groups, {list, {id, string}}}}, - #ejabberd_commands{name = srg_get_info, tags = [shared_roster_group], - desc = "Get info of a Shared Roster Group", - module = ?MODULE, function = srg_get_info, - args = [{group, binary}, {host, binary}], - result = {informations, {list, {information, {tuple, [{key, string}, {value, string}]}}}}}, - #ejabberd_commands{name = srg_get_members, tags = [shared_roster_group], - desc = "Get members of a Shared Roster Group", - module = ?MODULE, function = srg_get_members, - args = [{group, binary}, {host, binary}], - result = {members, {list, {member, string}}}}, - #ejabberd_commands{name = srg_user_add, tags = [shared_roster_group], - desc = "Add the JID user@host to the Shared Roster Group", - module = ?MODULE, function = srg_user_add, - args = [{user, binary}, {host, binary}, {group, binary}, {grouphost, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = srg_user_del, tags = [shared_roster_group], - desc = "Delete this JID user@host from the Shared Roster Group", - module = ?MODULE, function = srg_user_del, - args = [{user, binary}, {host, binary}, {group, binary}, {grouphost, binary}], - result = {res, rescode}}, - - #ejabberd_commands{name = send_message, tags = [stanza], - desc = "Send a message to a local or remote bare of full JID", - module = ?MODULE, function = send_message, - args = [{type, binary}, {from, binary}, {to, binary}, - {subject, binary}, {body, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = send_stanza_c2s, tags = [stanza], - desc = "Send a stanza as if sent from a c2s session", - module = ?MODULE, function = send_stanza_c2s, - args = [{user, binary}, {host, binary}, {resource, binary}, {stanza, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = privacy_set, tags = [stanza], - desc = "Send a IQ set privacy stanza for a local account", - module = ?MODULE, function = privacy_set, - args = [{user, binary}, {host, binary}, {xmlquery, binary}], - result = {res, rescode}}, - - #ejabberd_commands{name = stats, tags = [stats], - desc = "Get statistical value: registeredusers onlineusers onlineusersnode uptimeseconds", - module = ?MODULE, function = stats, - args = [{name, binary}], - result = {stat, integer}}, - #ejabberd_commands{name = stats_host, tags = [stats], - desc = "Get statistical value for this host: registeredusers onlineusers", - module = ?MODULE, function = stats, - args = [{name, binary}, {host, binary}], - result = {stat, integer}} - ]. - - -%%% -%%% Node -%%% - -compile(File) -> - compile:file(File). - -load_config(Path) -> - ok = ejabberd_config:load_file(Path). - -get_cookie() -> - atom_to_list(erlang:get_cookie()). - -remove_node(Node) -> - mnesia:del_table_copy(schema, list_to_atom(Node)), - ok. - -export2odbc(Host, Directory) -> - Tables = [ - {export_last, last}, - {export_offline, offline}, - {export_passwd, passwd}, - {export_private_storage, private_storage}, - {export_roster, roster}, - {export_vcard, vcard}, - {export_vcard_search, vcard_search}], - Export = fun({TableFun, Table}) -> - Filename = filename:join([Directory, atom_to_list(Table)++".txt"]), - io:format("Trying to export Mnesia table '~p' on Host '~s' to file '~s'~n", [Table, Host, Filename]), - Res = (catch ejd2odbc:TableFun(Host, Filename)), - io:format(" Result: ~p~n", [Res]) - end, - lists:foreach(Export, Tables), - ok. - - -%%% -%%% Accounts -%%% - -set_password(User, Host, Password) -> - case ejabberd_auth:set_password(User, Host, Password) of - ok -> - ok; - _ -> - error - end. - -%% Copied some code from ejabberd_commands.erl -check_password_hash(User, Host, PasswordHash, HashMethod) -> - AccountPass = ejabberd_auth:get_password_s(User, Host), - AccountPassHash = case HashMethod of - "md5" -> get_md5(AccountPass); - "sha" -> get_sha(AccountPass); - _ -> undefined - end, - case AccountPassHash of - undefined -> error; - PasswordHash -> ok; - _ -> error - end. -get_md5(AccountPass) -> - lists:flatten([io_lib:format("~.16B", [X]) - || X <- binary_to_list(crypto:md5(AccountPass))]). -get_sha(AccountPass) -> - lists:flatten([io_lib:format("~.16B", [X]) - || X <- binary_to_list(crypto:sha(AccountPass))]). - -num_active_users(Host, Days) -> - list_last_activity(Host, true, Days). - -%% Code based on ejabberd/src/web/ejabberd_web_admin.erl -list_last_activity(Host, Integral, Days) -> - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp = MegaSecs * 1000000 + Secs, - TS = TimeStamp - Days * 86400, - case catch mnesia:dirty_select( - last_activity, [{{last_activity, {'_', Host}, '$1', '_'}, - [{'>', '$1', TS}], - [{'trunc', {'/', - {'-', TimeStamp, '$1'}, - 86400}}]}]) of - {'EXIT', _Reason} -> - []; - Vals -> - Hist = histogram(Vals, Integral), - if - Hist == [] -> - 0; - true -> - Left = Days - length(Hist), - Tail = if - Integral -> - lists:duplicate(Left, lists:last(Hist)); - true -> - lists:duplicate(Left, 0) - end, - lists:nth(Days, Hist ++ Tail) - end - end. -histogram(Values, Integral) -> - histogram(lists:sort(Values), Integral, 0, 0, []). -histogram([H | T], Integral, Current, Count, Hist) when Current == H -> - histogram(T, Integral, Current, Count + 1, Hist); -histogram([H | _] = Values, Integral, Current, Count, Hist) when Current < H -> - if - Integral -> - histogram(Values, Integral, Current + 1, Count, [Count | Hist]); - true -> - histogram(Values, Integral, Current + 1, 0, [Count | Hist]) - end; -histogram([], _Integral, _Current, Count, Hist) -> - if - Count > 0 -> - lists:reverse([Count | Hist]); - true -> - lists:reverse(Hist) - end. - - -delete_old_users(Days) -> - %% Get the list of registered users - Users = ejabberd_auth:dirty_get_registered_users(), - - {removed, N, UR} = delete_old_users(Days, Users), - {ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}. - -delete_old_users_vhost(Host, Days) -> - %% Get the list of registered users - Users = ejabberd_auth:get_vh_registered_users(Host), - - {removed, N, UR} = delete_old_users(Days, Users), - {ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}. - -delete_old_users(Days, Users) -> - %% Convert older time - SecOlder = Days*24*60*60, - - %% Get current time - {MegaSecs, Secs, _MicroSecs} = now(), - TimeStamp_now = MegaSecs * 1000000 + Secs, - - %% For a user, remove if required and answer true - F = fun({LUser, LServer}) -> - %% Check if the user is logged - case ejabberd_sm:get_user_resources(LUser, LServer) of - %% If it isnt - [] -> - %% Look for his last_activity - case (get_lastactivity_module(LServer)):get_last_info(LUser, LServer) of - %% If it is - %% existent: - {ok, TimeStamp, _Status} -> - %% get his age - Sec = TimeStamp_now - TimeStamp, - %% If he is - if - %% younger than SecOlder: - Sec < SecOlder -> - %% do nothing - false; - %% older: - true -> - %% remove the user - ejabberd_auth:remove_user(LUser, LServer), - true - end; - %% nonexistent: - not_found -> - %% remove the user - ejabberd_auth:remove_user(LUser, LServer), - true - end; - %% Else - _ -> - %% do nothing - false - end - end, - %% Apply the function to every user in the list - Users_removed = lists:filter(F, Users), - {removed, length(Users_removed), Users_removed}. - -get_lastactivity_module(Server) -> - case lists:member(mod_last, gen_mod:loaded_modules(Server)) of - true -> mod_last; - _ -> mod_last_odbc - end. - - -%% -%% Ban account - -ban_account(User, Host, ReasonText) -> - Reason = prepare_reason(ReasonText), - kick_sessions(User, Host, Reason), - set_random_password(User, Host, Reason), - ok. - -kick_sessions(User, Server, Reason) -> - lists:map( - fun(Resource) -> - kick_this_session(User, Server, Resource, Reason) - end, - get_resources(User, Server)). - -get_resources(User, Server) -> - lists:map( - fun(Session) -> - element(3, Session#session.usr) - end, - get_sessions(User, Server)). - -get_sessions(User, Server) -> - LUser = jlib:nodeprep(User), - LServer = jlib:nameprep(Server), - Sessions = mnesia:dirty_index_read(session, {LUser, LServer}, #session.us), - true = is_list(Sessions), - Sessions. - -set_random_password(User, Server, Reason) -> - NewPass = build_random_password(Reason), - set_password_auth(User, Server, NewPass). - -build_random_password(Reason) -> - Date = jlib:timestamp_to_iso(calendar:universal_time()), - RandomString = randoms:get_string(), - <<"BANNED_ACCOUNT--", Date/binary, "--", RandomString/binary, "--", Reason/binary>>. - -set_password_auth(User, Server, Password) -> - ok = ejabberd_auth:set_password(User, Server, Password). - -prepare_reason([]) -> - <<"Kicked by administrator">>; -prepare_reason([Reason]) -> - Reason; -prepare_reason(Reason) when is_binary(Reason) -> - Reason. - -%%% -%%% Sessions -%%% - -num_resources(User, Host) -> - length(ejabberd_sm:get_user_resources(User, Host)). - -resource_num(User, Host, Num) -> - Resources = ejabberd_sm:get_user_resources(User, Host), - case (0 - lists:nth(Num, Resources); - false -> - lists:flatten(io_lib:format("Error: Wrong resource number: ~p", [Num])) - end. - -kick_session(User, Server, Resource, ReasonText) -> - kick_this_session(User, Server, Resource, prepare_reason(ReasonText)), - ok. - -kick_this_session(User, Server, Resource, Reason) -> - ejabberd_sm:route(jlib:make_jid(<<"">>, <<"">>, <<"">>), - jlib:make_jid(User, Server, Resource), - {broadcast, {exit, Reason}}). - -status_num(Host, Status) -> - length(get_status_list(Host, Status)). -status_num(Status) -> - status_num(<<"all">>, Status). -status_list(Host, Status) -> - Res = get_status_list(Host, Status), - [{U, S, R, P, St} || {U, S, R, P, St} <- Res]. -status_list(Status) -> - status_list(<<"all">>, Status). - - -get_status_list(Host, Status_required) -> - %% Get list of all logged users - Sessions = ejabberd_sm:dirty_get_my_sessions_list(), - %% Reformat the list - Sessions2 = [ {Session#session.usr, Session#session.sid, Session#session.priority} || Session <- Sessions], - Fhost = case Host of - <<"all">> -> - %% All hosts are requested, so dont filter at all - fun(_, _) -> true end; - _ -> - %% Filter the list, only Host is interesting - fun(A, B) -> A == B end - end, - Sessions3 = [ {Pid, Server, Priority} || {{_User, Server, _Resource}, {_, Pid}, Priority} <- Sessions2, apply(Fhost, [Server, Host])], - %% For each Pid, get its presence - Sessions4 = [ {catch ejabberd_c2s:get_presence(Pid), Server, Priority} || {Pid, Server, Priority} <- Sessions3], - %% Filter by status - Fstatus = case Status_required of - <<"all">> -> - fun(_, _) -> true end; - _ -> - fun(A, B) -> A == B end - end, - [{User, Server, Resource, Priority, stringize(Status_text)} - || {{User, Resource, Status, Status_text}, Server, Priority} <- Sessions4, - apply(Fstatus, [Status, Status_required])]. - -connected_users_info() -> - USRIs = dirty_get_sessions_list2(), - CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}), - lists:map( - fun([{U, S, R}, {Now, Pid}, Priority, Info]) -> - Conn = proplists:get_value(conn, Info), - {Ip, Port} = proplists:get_value(ip, Info), - IPS = inet_parse:ntoa(Ip), - NodeS = atom_to_list(node(Pid)), - Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds( - calendar:now_to_local_time(Now)), - PriorityI = case Priority of - PI when is_integer(PI) -> PI; - _ -> nil - end, - {[U, $@, S, $/, R], atom_to_list(Conn), IPS, Port, PriorityI, NodeS, Uptime} - end, - USRIs). - -connected_users_vhost(Host) -> - USRs = ejabberd_sm:get_vh_session_list(Host), - [ [U, $@, S, $/, R] || {U, S, R} <- USRs]. - -%% Code copied from ejabberd_sm.erl and customized -dirty_get_sessions_list2() -> - mnesia:dirty_select( - session, - [{#session{usr = '$1', sid = '$2', priority = '$3', info = '$4', _ = '_'}, - [], - [['$1', '$2', '$3', '$4']]}]). - -%% Make string more print-friendly -stringize(String) -> - %% Replace newline characters with other code - ejabberd_regexp:greplace(String, <<"\n">>, <<"\\n">>). - -set_presence(User, Host, Resource, Type, Show, Status, Priority) -> - Pid = ejabberd_sm:get_session_pid(User, Host, Resource), - USR = jlib:jid_to_string(jlib:make_jid(User, Host, Resource)), - US = jlib:jid_to_string(jlib:make_jid(User, Host, <<>>)), - Message = {route_xmlstreamelement, - {xmlel, <<"presence">>, - [{<<"from">>, USR}, {<<"to">>, US}, {<<"type">>, Type}], - [{xmlel, <<"show">>, [], [{xmlcdata, Show}]}, - {xmlel, <<"status">>, [], [{xmlcdata, Status}]}, - {xmlel, <<"priority">>, [], [{xmlcdata, Priority}]}]}}, - Pid ! Message. - -user_sessions_info(User, Host) -> - CurrentSec = calendar:datetime_to_gregorian_seconds({date(), time()}), - US = {User, Host}, - Sessions = case catch mnesia:dirty_index_read(session, US, #session.us) of - {'EXIT', _Reason} -> - []; - Ss -> - Ss - end, - lists:map( - fun(Session) -> - {_U, _S, Resource} = Session#session.usr, - {Now, Pid} = Session#session.sid, - {_U, _Resource, Status, StatusText} = ejabberd_c2s:get_presence(Pid), - Info = Session#session.info, - Priority = Session#session.priority, - Conn = proplists:get_value(conn, Info), - {Ip, Port} = proplists:get_value(ip, Info), - IPS = inet_parse:ntoa(Ip), - NodeS = atom_to_list(node(Pid)), - Uptime = CurrentSec - calendar:datetime_to_gregorian_seconds( - calendar:now_to_local_time(Now)), - {atom_to_list(Conn), IPS, Port, Priority, NodeS, Uptime, Status, Resource, StatusText} - end, - Sessions). - - -%%% -%%% Vcard -%%% - -set_nickname(User, Host, Nickname) -> - R = mod_vcard:process_sm_iq( - {jid, User, Host, <<>>, User, Host, <<>>}, - {jid, User, Host, <<>>, User, Host, <<>>}, - {iq, <<>>, set, <<>>, <<"en">>, - {xmlel, <<"vCard">>, [ - {<<"xmlns">>, <<"vcard-temp">>}], [ - {xmlel, <<"NICKNAME">>, [], [{xmlcdata, Nickname}]} - ] - }}), - case R of - {iq, <<>>, result, <<>>, _L, []} -> - ok; - _ -> - error - end. - -get_vcard(User, Host, Name) -> - [Res | _] = get_vcard_content(User, Host, [Name]), - Res. - -get_vcard(User, Host, Name, Subname) -> - [Res | _] = get_vcard_content(User, Host, [Name, Subname]), - Res. - -get_vcard_multi(User, Host, Name, Subname) -> - get_vcard_content(User, Host, [Name, Subname]). - -set_vcard(User, Host, Name, SomeContent) -> - set_vcard_content(User, Host, [Name], SomeContent). - -set_vcard(User, Host, Name, Subname, SomeContent) -> - set_vcard_content(User, Host, [Name, Subname], SomeContent). - - -%% -%% Internal vcard - -get_module_resource(Server) -> - case gen_mod:get_module_opt(Server, ?MODULE, module_resource, fun(A) -> A end, none) of - none -> list_to_binary(atom_to_list(?MODULE)); - R when is_binary(R) -> R - end. - -get_vcard_content(User, Server, Data) -> - [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), - JID = jlib:make_jid(User, Server, get_module_resource(Server)), - IQ = #iq{type = get, xmlns = ?NS_VCARD}, - IQr = Module:Function(JID, JID, IQ), - [A1] = IQr#iq.sub_el, - case A1#xmlel.children of - [_|_] -> - case get_vcard(Data, A1) of - [false] -> throw(error_no_value_found_in_vcard); - ElemList -> ?DEBUG("ELS ~p", [ElemList]), [xml:get_tag_cdata(Elem) || Elem <- ElemList] - end; - [] -> - throw(error_no_vcard_found) - end. - -get_vcard([<<"TEL">>, TelType], {_, _, _, OldEls}) -> - {TakenEl, _NewEls} = take_vcard_tel(TelType, OldEls, [], not_found), - [TakenEl]; - -get_vcard([Data1, Data2], A1) -> - case get_subtag(A1, Data1) of - [false] -> [false]; - A2List -> - lists:flatten([get_vcard([Data2], A2) || A2 <- A2List]) - end; - -get_vcard([Data], A1) -> - get_subtag(A1, Data). - -get_subtag(Xmlelement, Name) -> - [xml:get_subtag(Xmlelement, Name)]. - -set_vcard_content(User, Server, Data, SomeContent) -> - ContentList = case SomeContent of - [Bin | _] when is_binary(Bin) -> SomeContent; - Bin when is_binary(Bin) -> [SomeContent] - end, - [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}), - JID = jlib:make_jid(User, Server, get_module_resource(Server)), - IQ = #iq{type = get, xmlns = ?NS_VCARD}, - IQr = Module:Function(JID, JID, IQ), - - %% Get old vcard - A4 = case IQr#iq.sub_el of - [A1] -> - {_, _, _, A2} = A1, - update_vcard_els(Data, ContentList, A2); - [] -> - update_vcard_els(Data, ContentList, []) - end, - - %% Build new vcard - SubEl = {xmlel, <<"vCard">>, [{<<"xmlns">>,<<"vcard-temp">>}], A4}, - IQ2 = #iq{type=set, sub_el = SubEl}, - - Module:Function(JID, JID, IQ2), - ok. - -take_vcard_tel(TelType, [{xmlel, <<"TEL">>, _, SubEls}=OldEl | OldEls], NewEls, Taken) -> - {Taken2, NewEls2} = case lists:keymember(TelType, 2, SubEls) of - true -> {xml:get_subtag(OldEl, <<"NUMBER">>), NewEls}; - false -> {Taken, [OldEl | NewEls]} - end, - take_vcard_tel(TelType, OldEls, NewEls2, Taken2); -take_vcard_tel(TelType, [OldEl | OldEls], NewEls, Taken) -> - take_vcard_tel(TelType, OldEls, [OldEl | NewEls], Taken); -take_vcard_tel(_TelType, [], NewEls, Taken) -> - {Taken, NewEls}. - -update_vcard_els([<<"TEL">>, TelType], [TelValue], OldEls) -> - {_, NewEls} = take_vcard_tel(TelType, OldEls, [], not_found), - NewEl = {xmlel,<<"TEL">>,[], - [{xmlel,TelType,[],[]}, - {xmlel,<<"NUMBER">>,[],[{xmlcdata,TelValue}]}]}, - [NewEl | NewEls]; - -update_vcard_els(Data, ContentList, Els1) -> - Els2 = lists:keysort(2, Els1), - [Data1 | Data2] = Data, - NewEls = case Data2 of - [] -> - [{xmlel, Data1, [], [{xmlcdata,Content}]} || Content <- ContentList]; - [D2] -> - OldEl = case lists:keysearch(Data1, 2, Els2) of - {value, A} -> A; - false -> {xmlel, Data1, [], []} - end, - {xmlel, _, _, ContentOld1} = OldEl, - Content2 = [{xmlel, D2, [], [{xmlcdata,Content}]} || Content <- ContentList], - ContentOld2 = [A || {_, X, _, _} = A <- ContentOld1, X/=D2], - ContentOld3 = lists:keysort(2, ContentOld2), - ContentNew = lists:keymerge(2, Content2, ContentOld3), - [{xmlel, Data1, [], ContentNew}] - end, - Els3 = lists:keydelete(Data1, 2, Els2), - lists:keymerge(2, NewEls, Els3). - - -%%% -%%% Roster -%%% - -add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs) -> - case add_rosteritem(LocalUser, LocalServer, User, Server, Nick, Group, Subs, []) of - {atomic, ok} -> - push_roster_item(LocalUser, LocalServer, User, Server, {add, Nick, Subs, Group}), - ok; - _ -> - error - end. - -add_rosteritem(LU, LS, User, Server, Nick, Group, Subscription, Xattrs) -> - subscribe(LU, LS, User, Server, Nick, Group, Subscription, Xattrs). - -subscribe(LU, LS, User, Server, Nick, Group, Subscription, _Xattrs) -> - ItemEl = build_roster_item(User, Server, {add, Nick, Subscription, Group}), - mod_roster:set_items( - LU, LS, - {xmlel, <<"query">>, - [{<<"xmlns">>, <<"jabber:iq:roster">>}], - [ItemEl]}). - -delete_rosteritem(LocalUser, LocalServer, User, Server) -> - case unsubscribe(LocalUser, LocalServer, User, Server) of - {atomic, ok} -> - push_roster_item(LocalUser, LocalServer, User, Server, remove), - ok; - _ -> - error - end. - -unsubscribe(LU, LS, User, Server) -> - ItemEl = build_roster_item(User, Server, remove), - mod_roster:set_items( - LU, LS, - {xmlel, <<"query">>, - [{<<"xmlns">>, <<"jabber:iq:roster">>}], - [ItemEl]}). - -%% ----------------------------- -%% Get Roster -%% ----------------------------- - -get_roster(User, Server) -> - Items = ejabberd_hooks:run_fold(roster_get, Server, [], [{User, Server}]), - make_roster_xmlrpc(Items). - -%% Note: if a contact is in several groups, the contact is returned -%% several times, each one in a different group. -make_roster_xmlrpc(Roster) -> - lists:foldl( - fun(Item, Res) -> - JIDS = jlib:jid_to_string(Item#roster.jid), - Nick = Item#roster.name, - Subs = atom_to_list(Item#roster.subscription), - Ask = atom_to_list(Item#roster.ask), - Groups = case Item#roster.groups of - [] -> [<<>>]; - Gs -> Gs - end, - ItemsX = [{JIDS, Nick, Subs, Ask, Group} || Group <- Groups], - ItemsX ++ Res - end, - [], - Roster). - - -%%----------------------------- -%% Push Roster from file -%%----------------------------- - -push_roster(File, User, Server) -> - {ok, [Roster]} = file:consult(File), - subscribe_roster({User, Server, <<>>, User}, Roster). - -push_roster_all(File) -> - {ok, [Roster]} = file:consult(File), - subscribe_all(Roster). - -subscribe_all(Roster) -> - subscribe_all(Roster, Roster). -subscribe_all([], _) -> - ok; -subscribe_all([User1 | Users], Roster) -> - subscribe_roster(User1, Roster), - subscribe_all(Users, Roster). - -subscribe_roster(_, []) -> - ok; -%% Do not subscribe a user to itself -subscribe_roster({Name, Server, Group, Nick}, [{Name, Server, _, _} | Roster]) -> - subscribe_roster({Name, Server, Group, Nick}, Roster); -%% Subscribe Name2 to Name1 -subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick2} | Roster]) -> - subscribe(Name1, Server1, Name2, Server2, Nick2, Group2, <<"both">>, []), - subscribe_roster({Name1, Server1, Group1, Nick1}, Roster). - -push_alltoall(S, G) -> - Users = ejabberd_auth:get_vh_registered_users(S), - Users2 = build_list_users(G, Users, []), - subscribe_all(Users2), - ok. - -build_list_users(_Group, [], Res) -> - Res; -build_list_users(Group, [{User, Server}|Users], Res) -> - build_list_users(Group, Users, [{User, Server, Group, User}|Res]). - -%% @spec(LU, LS, U, S, Action) -> ok -%% Action = {add, Nick, Subs, Group} | remove -%% @doc Push to the roster of account LU@LS the contact U@S. -%% The specific action to perform is defined in Action. -push_roster_item(LU, LS, U, S, Action) -> - lists:foreach(fun(R) -> - push_roster_item(LU, LS, R, U, S, Action) - end, ejabberd_sm:get_user_resources(LU, LS)). - -push_roster_item(LU, LS, R, U, S, Action) -> - LJID = jlib:make_jid(LU, LS, R), - BroadcastEl = build_broadcast(U, S, Action), - ejabberd_sm:route(LJID, LJID, BroadcastEl), - Item = build_roster_item(U, S, Action), - ResIQ = build_iq_roster_push(Item), - ejabberd_router:route(LJID, LJID, ResIQ). - -build_roster_item(U, S, {add, Nick, Subs, Group}) -> - {xmlel, <<"item">>, - [{<<"jid">>, jlib:jid_to_string(jlib:make_jid(U, S, <<>>))}, - {<<"name">>, Nick}, - {<<"subscription">>, Subs}], - [{xmlel, <<"group">>, [], [{xmlcdata, Group}]}] - }; -build_roster_item(U, S, remove) -> - {xmlel, <<"item">>, - [{<<"jid">>, jlib:jid_to_string(jlib:make_jid(U, S, <<>>))}, - {<<"subscription">>, <<"remove">>}], - [] - }. - -build_iq_roster_push(Item) -> - {xmlel, <<"iq">>, - [{<<"type">>, <<"set">>}, {<<"id">>, <<"push">>}], - [{xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_ROSTER}], - [Item] - } - ] - }. - -build_broadcast(U, S, {add, _Nick, Subs, _Group}) -> - build_broadcast(U, S, list_to_atom(binary_to_list(Subs))); -build_broadcast(U, S, remove) -> - build_broadcast(U, S, none); -%% @spec (U::binary(), S::binary(), Subs::atom()) -> any() -%% Subs = both | from | to | none -build_broadcast(U, S, SubsAtom) when is_atom(SubsAtom) -> - {broadcast, {item, {U, S, <<>>}, SubsAtom}}. - -%%% -%%% Last Activity -%%% - -get_last(User, Server) -> - Mod = get_lastactivity_module(Server), - case ejabberd_sm:get_user_resources(User, Server) of - [] -> - case Mod:get_last_info(User, Server) of - not_found -> - "Never"; - {ok, Shift, _Status} -> - TimeStamp = {Shift div 1000000, - Shift rem 1000000, - 0}, - {{Year, Month, Day}, {Hour, Minute, Second}} = - calendar:now_to_local_time(TimeStamp), - lists:flatten( - io_lib:format( - "~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w", - [Year, Month, Day, Hour, Minute, Second])) - end; - _ -> - "Online" - end. - -set_last(User, Server, Timestamp, Status) -> - Mod = get_lastactivity_module(Server), - Mod:store_last_info(User, Server, Timestamp, Status). - -%%% -%%% Private Storage -%%% - -%% Example usage: -%% $ ejabberdctl private_set badlop localhost "\Cluth\" -%% $ ejabberdctl private_get badlop localhost aa bb -%% Cluth - -private_get(Username, Host, Element, Ns) -> - From = jlib:make_jid(Username, Host, <<>>), - To = jlib:make_jid(Username, Host, <<>>), - IQ = {iq, <<>>, get, ?NS_PRIVATE, <<>>, - {xmlel, <<"query">>, - [{<<"xmlns">>,?NS_PRIVATE}], - [{xmlel, Element, [{<<"xmlns">>, Ns}], []}]}}, - ResIq = mod_private:process_sm_iq(From, To, IQ), - [{xmlel, <<"query">>, - [{<<"xmlns">>, <<"jabber:iq:private">>}], - [SubEl]}] = ResIq#iq.sub_el, - binary_to_list(xml:element_to_binary(SubEl)). - -private_set(Username, Host, ElementString) -> - case xml_stream:parse_element(ElementString) of - {error, Error} -> - io:format("Error found parsing the element:~n ~p~nError: ~p~n", - [ElementString, Error]), - error; - Xml -> - private_set2(Username, Host, Xml) - end. - -private_set2(Username, Host, Xml) -> - From = jlib:make_jid(Username, Host, <<>>), - To = jlib:make_jid(Username, Host, <<>>), - IQ = {iq, <<>>, set, ?NS_PRIVATE, <<>>, - {xmlel, <<"query">>, - [{<<"xmlns">>, ?NS_PRIVATE}], - [Xml]}}, - mod_private:process_sm_iq(From, To, IQ), - ok. - -%%% -%%% Shared Roster Groups -%%% - -srg_create(Group, Host, Name, Description, Display) -> - DisplayList = case Display of - <<>> -> []; - _ -> ejabberd_regexp:split(Display, <<"\\\\n">>) - end, - Opts = [{name, Name}, - {displayed_groups, DisplayList}, - {description, Description}], - {atomic, ok} = mod_shared_roster:create_group(Host, Group, Opts), - ok. - -srg_delete(Group, Host) -> - {atomic, ok} = mod_shared_roster:delete_group(Host, Group), - ok. - -srg_list(Host) -> - lists:sort(mod_shared_roster:list_groups(Host)). - -srg_get_info(Group, Host) -> - Opts = case mod_shared_roster:get_group_opts(Host,Group) of - Os when is_list(Os) -> Os; - error -> [] - end, - [{jlib:atom_to_binary(Title), - io_lib:format("~p", [btl(Value)])} || {Title, Value} <- Opts]. - -btl([]) -> []; -btl([B|L]) -> [btl(B)|btl(L)]; -btl(B) -> binary_to_list(B). - -srg_get_members(Group, Host) -> - Members = mod_shared_roster:get_group_explicit_users(Host,Group), - [jlib:jid_to_string(jlib:make_jid(MUser, MServer, <<>>)) - || {MUser, MServer} <- Members]. - -srg_user_add(User, Host, Group, GroupHost) -> - {atomic, ok} = mod_shared_roster:add_user_to_group(GroupHost, {User, Host}, Group), - ok. - -srg_user_del(User, Host, Group, GroupHost) -> - {atomic, ok} = mod_shared_roster:remove_user_from_group(GroupHost, {User, Host}, Group), - ok. - - -%%% -%%% Stanza -%%% - -%% @doc Send a message to a Jabber account. -%% @spec (Type::binary(), From::binary(), To::binary(), Subject::binary(), Body::binary()) -> ok -send_message(Type, From, To, Subject, Body) -> - Packet = build_packet(Type, Subject, Body), - send_packet_all_resources(From, To, Packet). - -%% @doc Send a packet to a Jabber account. -%% If a resource was specified in the JID, -%% the packet is sent only to that specific resource. -%% If no resource was specified in the JID, -%% and the user is remote or local but offline, -%% the packet is sent to the bare JID. -%% If the user is local and is online in several resources, -%% the packet is sent to all its resources. -send_packet_all_resources(FromJIDString, ToJIDString, Packet) -> - FromJID = jlib:string_to_jid(FromJIDString), - ToJID = jlib:string_to_jid(ToJIDString), - ToUser = ToJID#jid.user, - ToServer = ToJID#jid.server, - case ToJID#jid.resource of - <<>> -> - send_packet_all_resources(FromJID, ToUser, ToServer, Packet); - Res -> - send_packet_all_resources(FromJID, ToUser, ToServer, Res, Packet) - end. - -send_packet_all_resources(FromJID, ToUser, ToServer, Packet) -> - case ejabberd_sm:get_user_resources(ToUser, ToServer) of - [] -> - send_packet_all_resources(FromJID, ToUser, ToServer, <<>>, Packet); - ToResources -> - lists:foreach( - fun(ToResource) -> - send_packet_all_resources(FromJID, ToUser, ToServer, - ToResource, Packet) - end, - ToResources) - end. - -send_packet_all_resources(FromJID, ToU, ToS, ToR, Packet) -> - ToJID = jlib:make_jid(ToU, ToS, ToR), - ejabberd_router:route(FromJID, ToJID, Packet). - -build_packet(Type, Subject, Body) -> - Tail = if Subject == <<"">>; Type == <<"chat">> -> []; - true -> [{xmlel, <<"subject">>, [], [{xmlcdata, Subject}]}] - end, - {xmlel, <<"message">>, - [{<<"type">>, Type}, {<<"id">>, randoms:get_string()}], - [{xmlel, <<"body">>, [], [{xmlcdata, Body}]} | Tail] - }. - -send_stanza_c2s(Username, Host, Resource, Stanza) -> - C2sPid = ejabberd_sm:get_session_pid(Username, Host, Resource), - XmlEl = xml_stream:parse_element(Stanza), - p1_fsm:send_event(C2sPid, {xmlstreamelement, XmlEl}). - -privacy_set(Username, Host, QueryS) -> - From = jlib:make_jid(Username, Host, <<"">>), - To = jlib:make_jid(<<"">>, Host, <<"">>), - QueryEl = xml_stream:parse_element(QueryS), - StanzaEl = {xmlel, <<"iq">>, [{<<"type">>, <<"set">>}], [QueryEl]}, - IQ = jlib:iq_query_info(StanzaEl), - ejabberd_hooks:run_fold( - privacy_iq_set, - Host, - {error, ?ERR_FEATURE_NOT_IMPLEMENTED}, - [From, To, IQ] - ), - ok. - -%%% -%%% Stats -%%% - -stats(Name) -> - case Name of - <<"uptimeseconds">> -> trunc(element(1, erlang:statistics(wall_clock))/1000); - <<"registeredusers">> -> lists:foldl(fun(Host, Sum) -> ejabberd_auth:get_vh_registered_users_number(Host) + Sum end, 0, ?MYHOSTS); - <<"onlineusersnode">> -> length(ejabberd_sm:dirty_get_my_sessions_list()); - <<"onlineusers">> -> length(ejabberd_sm:dirty_get_sessions_list()) - end. - -stats(Name, Host) -> - case Name of - <<"registeredusers">> -> ejabberd_auth:get_vh_registered_users_number(Host); - <<"onlineusers">> -> length(ejabberd_sm:get_vh_session_list(Host)) - end. - - - -%%----------------------------- -%% Purge roster items -%%----------------------------- - -process_rosteritems(ActionS, SubsS, AsksS, UsersS, ContactsS) -> - Action = case ActionS of - "list" -> list; - "delete" -> delete - end, - - Subs = lists:foldl( - fun(any, _) -> [none, from, to, both]; - (Sub, Subs) -> [Sub | Subs] - end, - [], - [list_to_atom(S) || S <- string:tokens(SubsS, ":")] - ), - - Asks = lists:foldl( - fun(any, _) -> [none, out, in]; - (Ask, Asks) -> [Ask | Asks] - end, - [], - [list_to_atom(S) || S <- string:tokens(AsksS, ":")] - ), - - Users = lists:foldl( - fun("any", _) -> ["*", "*@*"]; - (U, Us) -> [U | Us] - end, - [], - [S || S <- string:tokens(UsersS, ":")] - ), - - Contacts = lists:foldl( - fun("any", _) -> ["*", "*@*"]; - (U, Us) -> [U | Us] - end, - [], - [S || S <- string:tokens(ContactsS, ":")] - ), - - rosteritem_purge({Action, Subs, Asks, Users, Contacts}). - -%% @spec ({Action::atom(), Subs::[atom()], Asks::[atom()], User::string(), Contact::string()}) -> {atomic, ok} -rosteritem_purge(Options) -> - Num_rosteritems = mnesia:table_info(roster, size), - io:format("There are ~p roster items in total.~n", [Num_rosteritems]), - Key = mnesia:dirty_first(roster), - rip(Key, Options, {0, Num_rosteritems, 0, 0}, []). - -rip('$end_of_table', _Options, Counters, Res) -> - print_progress_line(Counters), - Res; -rip(Key, Options, {Pr, NT, NV, ND}, Res) -> - Key_next = mnesia:dirty_next(roster, Key), - {Action, _, _, _, _} = Options, - {ND2, Res2} = case decide_rip(Key, Options) of - true -> - Jids = apply_action(Action, Key), - {ND+1, [Jids | Res]}; - false -> - {ND, Res} - end, - NV2 = NV+1, - Pr2 = print_progress_line({Pr, NT, NV2, ND2}), - rip(Key_next, Options, {Pr2, NT, NV2, ND2}, Res2). - -apply_action(list, Key) -> - {User, Server, JID} = Key, - {RUser, RServer, _} = JID, - Jid1string = <>, - Jid2string = <>, - io:format("Matches: ~s ~s~n", [Jid1string, Jid2string]), - {Jid1string, Jid2string}; -apply_action(delete, Key) -> - R = apply_action(list, Key), - mnesia:dirty_delete(roster, Key), - R. - -print_progress_line({_Pr, 0, _NV, _ND}) -> - ok; -print_progress_line({Pr, NT, NV, ND}) -> - Pr2 = trunc((NV/NT)*100), - case Pr == Pr2 of - true -> - ok; - false -> - io:format("Progress ~p% - visited ~p - deleted ~p~n", [Pr2, NV, ND]) - end, - Pr2. - -decide_rip(Key, {_Action, Subs, Asks, User, Contact}) -> - case catch mnesia:dirty_read(roster, Key) of - [RI] -> - lists:member(RI#roster.subscription, Subs) - andalso lists:member(RI#roster.ask, Asks) - andalso decide_rip_jid(RI#roster.us, User) - andalso decide_rip_jid(RI#roster.jid, Contact); - _ -> - false - end. - -%% Returns true if the server of the JID is included in the servers -decide_rip_jid({UName, UServer, _UResource}, Match_list) -> - decide_rip_jid({UName, UServer}, Match_list); -decide_rip_jid({UName, UServer}, Match_list) -> - lists:any( - fun(Match_string) -> - MJID = jlib:string_to_jid(list_to_binary(Match_string)), - MName = MJID#jid.luser, - MServer = MJID#jid.lserver, - Is_server = is_glob_match(UServer, MServer), - case MName of - <<>> when UName == <<>> -> - Is_server; - <<>> -> - false; - _ -> - Is_server - andalso is_glob_match(UName, MName) - end - end, - Match_list). - -%% Copied from ejabberd-2.0.0/src/acl.erl -is_regexp_match(String, RegExp) -> - case ejabberd_regexp:run(String, RegExp) of - nomatch -> - false; - match -> - true; - {error, ErrDesc} -> - io:format( - "Wrong regexp ~p in ACL: ~p", - [RegExp, ErrDesc]), - false - end. -is_glob_match(String, <<"!", Glob/binary>>) -> - not is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)); -is_glob_match(String, Glob) -> - is_regexp_match(String, ejabberd_regexp:sh_to_awk(Glob)). diff --git a/mod_admin_extra/src/mod_ecomm_test.erl b/mod_admin_extra/src/mod_ecomm_test.erl deleted file mode 100644 index 99ff641..0000000 --- a/mod_admin_extra/src/mod_ecomm_test.erl +++ /dev/null @@ -1,426 +0,0 @@ -%%%------------------------------------------------------------------- -%%% File : mod_ecomm_test.erl -%%% Author : Badlop -%%% Purpose : Simple commands for testing -%%% Created : 10 Aug 2008 by Badlop -%%% -%%% -%%% ejabberd, Copyright (C) 2002-2008 ProcessOne -%%% -%%% This program is free software; you can redistribute it and/or -%%% modify it under the terms of the GNU General Public License as -%%% published by the Free Software Foundation; either version 2 of the -%%% License, or (at your option) any later version. -%%% -%%% This program is distributed in the hope that it will be useful, -%%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -%%% General Public License for more details. -%%% -%%% You should have received a copy of the GNU General Public License along -%%% with this program; if not, write to the Free Software Foundation, Inc., -%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -%%% -%%%------------------------------------------------------------------- - --module(mod_ecomm_test). --author('badlop@process-one.net'). - --behaviour(gen_mod). - --export([start/2, stop/1, - %% Take: test arguments - take_integer/1, - take_string/1, - take_integer_string/2, - take_tuple_2integer/1, - take_tuple_2string/1, - take_list_integer/1, - take_list_string/1, - %% Echo: test arguments and result - echo_integer/1, - echo_string/1, - echo_integer_string/2, - echo_list_integer/1, - echo_list_string/1, - echo_integer_list_string/2, - echo_isatils/4, - %% Tell: test result - tell_atom/1, - tell_rescode/1, - tell_restuple/1, - tell_tuple_3integer/0, - tell_tuple_3string/0, - tell_tuple_3atom/0, - tell_tuple_3list/0, - tell_list_3integer/0, - tell_list_3string/0, - tell_list_3atom/0, - tell_list_3tuple/0, - %% Realistic - this_crashes/1, - this_wrong_args/1, - this_wrong_return/0, - pow/2, seq/2, substrs/1, splitjid/1, splitjids/1 - ]). - --include("ejabberd.hrl"). --include("ejabberd_commands.hrl"). --include("jlib.hrl"). - -start(_Host, _Opts) -> - ejabberd_commands:register_commands(commands()). - -stop(_Host) -> - ejabberd_commands:unregister_commands(commands()). - -%%% -%%% ejabberd commands -%%% - -commands() -> - [ - - #ejabberd_commands{name = take_integer, tags = [test], - desc = "Take Integer in args, give Integer zero", - module = ?MODULE, function = take_integer, - args = [{thisinteger, integer}], - result = {zero, integer}}, - - #ejabberd_commands{name = take_string, tags = [test], - desc = "Take String, give Integer zero", - module = ?MODULE, function = take_string, - args = [{thisstring, string}], - result = {zero, integer}}, - - #ejabberd_commands{name = take_integer_string, tags = [test], - desc = "Take integer and string, give Integer zero", - module = ?MODULE, function = take_integer_string, - args = [{thisinteger, integer}, {thisstring, string}], - result = {zero, integer}}, - - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = take_tuple_2integer, tags = [test], - desc = "Take Tuple of two integers, give Integer zero", - module = ?MODULE, function = take_tuple_2integer, - args = [{thistuple, {tuple, [{thisinteger1, integer}, {thisinteger2, integer}]}}], - result = {zero, integer}}, - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = take_tuple_2string, tags = [test], - desc = "Take Tuple of two strings, give Integer zero", - module = ?MODULE, function = take_tuple_2string, - args = [{thistuple, {tuple, [{thisstring1, string}, {thisstring2, string}]}}], - result = {zero, integer}}, - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = take_list_integer, tags = [test], - desc = "Take List of integers, give Integer zero", - module = ?MODULE, function = take_list_integer, - args = [{thislist, {list, {thisinteger, integer}}}], - result = {zero, integer}}, - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = take_list_string, tags = [test], - desc = "Take List of strings, give Integer zero", - module = ?MODULE, function = take_list_string, - args = [{thislist, {list, {thisstring, string}}}], - result = {zero, integer}}, - - #ejabberd_commands{name = echo_integer, tags = [test], - desc = "Echo Integer", - module = ?MODULE, function = echo_integer, - args = [{thisinteger, integer}], - result = {thatinteger, integer}}, - #ejabberd_commands{name = echo_string, tags = [test], - desc = "Echo String", - module = ?MODULE, function = echo_string, - args = [{thisstring, string}], - result = {thatstring, string}}, - #ejabberd_commands{name = echo_integer_string, tags = [test], - desc = "Echo integer and string, in result as a tuple", - module = ?MODULE, function = echo_integer_string, - args = [{thisinteger, integer}, {thisstring, string}], - result = {thistuple, {tuple, [{thisinteger, integer}, {thisstring, string}]}}}, - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = echo_list_integer, tags = [test], - desc = "Echo List of integers", - module = ?MODULE, function = echo_list_integer, - args = [{thislist, {list, {thisinteger, integer}}}], - result = {thatlist, {list, {thatinteger, integer}}}}, - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = echo_list_string, tags = [test], - desc = "Echo List of strings", - module = ?MODULE, function = echo_list_string, - args = [{thislist, {list, {thisstring, string}}}], - result = {thatlist, {list, {thatstring, string}}}}, - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = echo_integer_list_string, tags = [test], - desc = "Echo an integer and List of strings", - module = ?MODULE, function = echo_integer_list_string, - args = [{thisinteger, integer}, {thislist, {list, {thisstring, string}}}], - result = {thistuple, {tuple, [{thatinteger, integer}, {thatlist, {list, {thatstring, string}}}]}}}, - %% Not supported by ejabberd_ctl - #ejabberd_commands{name = echo_isatils, tags = [test], - desc = "Echo integer, string, atom and tuple of integer and list of strings", - module = ?MODULE, function = echo_isatils, - args = [{thisinteger, integer}, - {thisstring, string}, - {thisatom, atom}, - {thistuple, {tuple, [ - {listlen, integer}, - {thislist, {list, {contentstring, string}}} - ]}} - ], - result = {results, {tuple, [{thatinteger, integer}, - {thatstring, string}, - {thatatom, atom}, - {thattuple, {tuple, [ - {listlen, integer}, - {thatlist, {list, {contentstring, string}}} - ]}} - ]}}}, - - #ejabberd_commands{name = tell_atom, tags = [test], - desc = "Tell Atom, give Integer zero", - module = ?MODULE, function = tell_atom, - args = [{thisinteger, integer}], - result = {thisatom, atom}}, - #ejabberd_commands{name = tell_rescode, tags = [test], - desc = "Tell rescode", - module = ?MODULE, function = tell_rescode, - args = [{thisinteger, integer}], - result = {res, rescode}}, - #ejabberd_commands{name = tell_restuple, tags = [test], - desc = "Tell restuple", - module = ?MODULE, function = tell_restuple, - args = [{thisinteger, integer}], - result = {res, restuple}}, - #ejabberd_commands{name = tell_tuple_3integer, tags = [test], - desc = "Tell a tuple with 3 integers", - module = ?MODULE, function = tell_tuple_3integer, - args = [], - result = {thattuple, {tuple, [{first, integer}, - {second, integer}, - {third, integer}]}}}, - #ejabberd_commands{name = tell_tuple_3string, tags = [test], - desc = "Tell a tuple with 3 strings", - module = ?MODULE, function = tell_tuple_3string, - args = [], - result = {thattuple, {tuple, [{first, string}, - {second, string}, - {third, string}]}}}, - #ejabberd_commands{name = tell_tuple_3atom, tags = [test], - desc = "Tell a tuple with 3 atoms", - module = ?MODULE, function = tell_tuple_3atom, - args = [], - result = {thattuple, {tuple, [{first, atom}, - {second, atom}, - {third, atom}]}}}, - #ejabberd_commands{name = tell_tuple_3list, tags = [test], - desc = "Tell a tuple with 3 lists", - module = ?MODULE, function = tell_tuple_3list, - args = [], - result = {thattuple, {tuple, - [{first, {list, - {thisinteger, integer}}}, - {second, {list, - {thisstring, string}}}, - {third, {list, - {thisatom, atom}}}]}}}, - - #ejabberd_commands{name = tell_list_3integer, tags = [test], - desc = "Tell a list with 3 integers", - module = ?MODULE, function = tell_list_3integer, - args = [], - result = {thatlist, {list, {thisinteger, integer}}}}, - #ejabberd_commands{name = tell_list_3string, tags = [test], - desc = "Tell a list with 3 strings", - module = ?MODULE, function = tell_list_3string, - args = [], - result = {thatlist, {list, {thisstring, string}}}}, - #ejabberd_commands{name = tell_list_3atom, tags = [test], - desc = "Tell a list with 3 atoms", - module = ?MODULE, function = tell_list_3atom, - args = [], - result = {thatlist, {list, {thisatom, atom}}}}, - #ejabberd_commands{name = tell_list_3tuple, tags = [test], - desc = "Tell a list with 3 tuples", - module = ?MODULE, function = tell_list_3tuple, - args = [], - result = {thatlist, {list, {thistuple, - {tuple, - [{thisinteger, integer}, - {thistring, string}, - {thisatom, atom}]}}}}}, - - #ejabberd_commands{name = this_crashes, tags = [test], - desc = "This command crashes: test+5", - module = ?MODULE, function = this_crashes, - args = [{aninteger, integer}], - result = {result, integer}}, - #ejabberd_commands{name = this_wrong_args, tags = [test], - desc = "This problematic command defines 2 arguments but function expects 1", - module = ?MODULE, function = this_wrong_args, - args = [{a, integer}, {b, integer}], - result = {result, integer}}, - #ejabberd_commands{name = this_wrong_return, tags = [test], - desc = "This problematic command doesn't give a proper return", - module = ?MODULE, function = this_wrong_return, - args = [], - result = {result, integer}}, - - #ejabberd_commands{name = pow, tags = [test], - desc = "Return the power of base for exponent", - longdesc = "This is an example command. The formula is:\n" - " power = base ^ exponent", - module = ?MODULE, function = pow, - args = [{base, integer}, {exponent, integer}], - result = {power, integer}}, - - #ejabberd_commands{name = seq, tags = [test], - desc = "Return list of integers between two integers", - module = ?MODULE, function = seq, - args = [{from, integer}, {to, integer}], - result = {sequence, {list, {intermediate, integer}}}}, - - #ejabberd_commands{name = substrs, tags = [test], - desc = "Return list of substrings of length increasing", - module = ?MODULE, function = substrs, - args = [{word, string}], - result = {substrings, {list, {miniword, string}}}}, - - #ejabberd_commands{name = splitjid, tags = [test], - desc = "Split JID in parts: user, server, resource", - module = ?MODULE, function = splitjid, - args = [{jid, string}], - result = {jidparts, {tuple, [{user, string}, - {server, string}, - {resource, string}]}}}, - - %% Not supported by ejabberd_ctl because uses 'list' in the arguments - #ejabberd_commands{name = splitjids, tags = [test], - desc = "Split JIDs in parts: user, server, resource", - module = ?MODULE, function = splitjids, - args = [{jids, {list, {jid, string}}}], - result = {jidsparts, - {list, {jidparts, - {tuple, [{user, string}, - {server, string}, - {resource, string}]}}}}} - - ]. - -%%% -%%% Take -%%% - -take_integer(A) when is_integer(A) -> 0. -take_string(A) when is_list(A) -> 0. -take_integer_string(A, B) - when is_integer(A) and is_list(B) -> - 0. -take_tuple_2integer({A, B}) - when is_integer(A) and is_integer(B) -> - 0. -take_tuple_2string({A, B}) - when is_list(A) and is_list(B) -> - 0. -take_list_integer(L) - when is_list(L) -> - true = lists:all(fun(A) -> is_integer(A) end, L), - 0. -take_list_string(L) - when is_list(L) -> - true = lists:all(fun(A) -> is_list(A) end, L), - 0. - -%%% -%%% Echo -%%% - -echo_integer(A) when is_integer(A) -> A. -echo_string(A) when is_list(A) -> A. -echo_integer_string(A, B) when is_integer(A) and is_list(B) -> {A, B}. -echo_list_integer(L) - when is_list(L) -> - true = lists:all(fun(A) -> is_integer(A) end, L), - L. -echo_list_string(L) - when is_list(L) -> - true = lists:all(fun(A) -> is_list(A) end, L), - L. -echo_integer_list_string(I, L) - when is_integer(I) and is_list(L) -> - true = lists:all(fun(A) -> is_list(A) end, L), - {I, L}. -echo_isatils(I, S, A, {II, L}) - when is_integer(I) and is_list(S) and is_atom(A) and is_integer(II) and is_list(L) -> - true = lists:all(fun(SS) -> is_list(SS) end, L), - {I, S, A, {I, L}}. - - -%%% -%%% Tell -%%% - -tell_atom(0) -> zero; -tell_atom(1) -> one; -tell_atom(A) when is_integer(A) -> greater_than_one. - -tell_rescode(0) -> ok; -tell_rescode(1) -> true; -tell_rescode(2) -> error; -tell_rescode(3) -> false; -tell_rescode(4) -> whatever. - -tell_restuple(0) -> {ok, "All OK"}; -tell_restuple(1) -> {true, "Successful result"}; -tell_restuple(2) -> {error, "This is an error message"}. - -tell_tuple_3integer() -> {123, 456, 789}. -tell_tuple_3string() -> {"Tell", "me", "a tuple please"}. -tell_tuple_3atom() -> {ok, works, perfectly}. -tell_tuple_3list() -> {[1, 23, 456], ["Tell", "me"], [all, is, ok]}. - -tell_list_3integer() -> [123, 456, 789]. -tell_list_3string() -> ["Tell", "me", "a tuple please"]. -tell_list_3atom() -> [ok, works, perfectly]. -tell_list_3tuple() -> - [{123, "abcdefghijkl", first}, - {593, "this string", morning}, - {999, "Sleeping dog", not_seen}]. - - -%%% -%%% Realistic -%%% - -%% This function will crash for sure -this_crashes(Integer) -> - test + Integer. - -this_wrong_args(Integer) -> - Integer + 1. - -this_wrong_return() -> - "this is a string". - -pow(Base, Exponent) -> - PowFloat = math:pow(Base, Exponent), - round(PowFloat). - -seq(From, To) -> - lists:seq(From, To). - -%% For "stick" returns: s st sti stic stick -substrs(Word) -> - Lengths = lists:seq(1, string:len(Word)), - [string:substr(Word, 1, Length) || Length <- Lengths]. - -splitjid(String) -> - JID = jlib:string_to_jid(String), - {JID#jid.user, - JID#jid.server, - JID#jid.resource}. - -splitjids(Strings) -> - [splitjid(String) || String <- Strings]. - diff --git a/mod_muc_admin/COPYING b/mod_muc_admin/COPYING deleted file mode 100644 index e21e8c4..0000000 --- a/mod_muc_admin/COPYING +++ /dev/null @@ -1,343 +0,0 @@ -As a special exception, the authors give permission to link this program -with the OpenSSL library and distribute the resulting binary. - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/mod_muc_admin/ChangeLog b/mod_muc_admin/ChangeLog deleted file mode 100644 index 5ebbea3..0000000 --- a/mod_muc_admin/ChangeLog +++ /dev/null @@ -1,80 +0,0 @@ -2009-07-01 Badlop - - * src/mod_muc_admin.erl: Fix change_room_option - -2009-06-02 Badlop - - * src/mod_muc_admin.erl: Destroy the room before forgetting it. - -2008-12-02 Badlop - - * src/mod_muc_admin.erl: Include mod_muc_room.hrl - * README.txt: Likewise - -2008-11-17 Badlop - - * src/mod_muc_admin.erl: Fix include of web hrl (thanks to Johnny) - -2008-10-12 Badlop - - * src/mod_muc_admin.erl: Update from ctl to commands (EJAB-694) - -2008-09-30 Badlop - - * src/mod_muc_admin.erl: Update record definitions to ejabberd - trunk SVN - -2008-05-16 Badlop - - * src/mod_muc_admin.erl: New exported function - set_affiliation/4 (thanks to Darren Ferguson) - -2008-05-12 Badlop - - * src/mod_muc_admin.erl: Added new function: change_room_option/4 - -2008-05-06 Badlop - - * src/mod_muc_admin.erl: New exported functions create_room and - destroy_room (thanks to Darren Ferguson) - -2008-04-04 Badlop - - * src/mod_muc_admin.erl: New command muc-create-file to create the - rooms indicated in the file - -2008-03-29 Badlop - - * src/mod_muc_admin.erl: Improvements in the list of rooms of web - admin: show timestamp of last message, sorting by any column. - -2008-03-19 Badlop - - * src/mod_muc_admin.erl (join): Copied the new function - string:join/2 introduced in Erlang R12 - - * README.txt: Clarified requirements - - * src/mod_muc_admin.erl (split_roomjid): Small fix - -2008-02-01 Badlop - - * src/mod_muc_admin.erl: New command: muc-unregister-nick. - -2007-12-26 Badlop - - * src/mod_muc_admin.erl: Translate menu items of webadmin hooks in - each module (EJAB-485) - -2007-11-15 Badlop - - * src/mod_muc_admin.erl: New command: muc-destroy-file. - -2007-09-09 Badlop - - * src/mod_muc_admin.erl: Added Web Admin and List rooms. - -2007-09-08 Badlop - - * mod_muc_admin: Initial commit. - diff --git a/mod_muc_admin/README.txt b/mod_muc_admin/README.txt deleted file mode 100644 index 272a35a..0000000 --- a/mod_muc_admin/README.txt +++ /dev/null @@ -1,43 +0,0 @@ - - - mod_muc_admin - Administrative features for MUC - - NOTE: This module is included in ejabberd since 15.04 - - Homepage: http://www.ejabberd.im/mod_muc_admin - Author: Badlop - -This module implements several ejabberd commands that can be -executed using ejabberdctl. - -It also implements Web Admin pages to view the list of existing -rooms. - - - CONFIGURATION - ============= - -Add the module to your ejabberd.yml, on the modules section: -modules: - mod_muc_admin: {} - - - EJABBERD COMMANDS - ================= - -Description of some commands: - - - muc-unusued-* - Those commands related to MUC require an ejabberd version newer than 1.1.x. - The room characteristics used to decide if a room is unusued: - - Days since the last message or subject change: - greater or equal to the command argument - - Number of participants: 0 - - Persistent: not important - - Has history: not important - - Days since last join, leave, room config or affiliation edit: - not important - - Just created: no - Note that ejabberd does not keep room history after a module restart, so - the history of all rooms is emtpy after a module or server start. - diff --git a/mod_muc_admin/conf/mod_muc_admin.yml b/mod_muc_admin/conf/mod_muc_admin.yml deleted file mode 100644 index 9d22951..0000000 --- a/mod_muc_admin/conf/mod_muc_admin.yml +++ /dev/null @@ -1,2 +0,0 @@ -modules: - mod_muc_admin: {} diff --git a/mod_muc_admin/mod_muc_admin.spec b/mod_muc_admin/mod_muc_admin.spec deleted file mode 100644 index 128d534..0000000 --- a/mod_muc_admin/mod_muc_admin.spec +++ /dev/null @@ -1,5 +0,0 @@ -author: "Badlop " -category: "admin" -summary: "Administrative features for MUC" -home: "https://github.com/processone/ejabberd-contrib/tree/master/" -url: "git@github.com:processone/ejabberd-contrib.git" diff --git a/mod_muc_admin/src/mod_muc_admin.erl b/mod_muc_admin/src/mod_muc_admin.erl deleted file mode 100644 index 5408d94..0000000 --- a/mod_muc_admin/src/mod_muc_admin.erl +++ /dev/null @@ -1,876 +0,0 @@ -%%%---------------------------------------------------------------------- -%%% File : mod_muc_admin.erl -%%% Author : Badlop -%%% Purpose : Tools for additional MUC administration -%%% Created : 8 Sep 2007 by Badlop -%%% Id : $Id: mod_muc_admin.erl 1133 2012-10-17 22:13:06Z badlop $ -%%%---------------------------------------------------------------------- - --module(mod_muc_admin). --author('badlop@ono.com'). - --behaviour(gen_mod). - --export([ - start/2, stop/1, % gen_mod API - muc_online_rooms/1, - muc_unregister_nick/1, - create_room/3, destroy_room/3, - create_rooms_file/1, destroy_rooms_file/1, - rooms_unused_list/2, rooms_unused_destroy/2, - get_room_occupants/2, - get_room_occupants_number/2, - send_direct_invitation/4, - change_room_option/4, - set_room_affiliation/4, - get_room_affiliations/2, - web_menu_main/2, web_page_main/2, % Web Admin API - web_menu_host/3, web_page_host/3 - ]). - --include("ejabberd.hrl"). --include("logger.hrl"). --include("jlib.hrl"). --include("mod_muc_room.hrl"). --include("ejabberd_http.hrl"). --include("ejabberd_web_admin.hrl"). --include("ejabberd_commands.hrl"). - -%% Copied from mod_muc/mod_muc.erl --record(muc_online_room, {name_host, pid}). - -%%---------------------------- -%% gen_mod -%%---------------------------- - -start(Host, _Opts) -> - ejabberd_commands:register_commands(commands()), - ejabberd_hooks:add(webadmin_menu_main, ?MODULE, web_menu_main, 50), - ejabberd_hooks:add(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50), - ejabberd_hooks:add(webadmin_page_main, ?MODULE, web_page_main, 50), - ejabberd_hooks:add(webadmin_page_host, Host, ?MODULE, web_page_host, 50). - -stop(Host) -> - ejabberd_commands:unregister_commands(commands()), - ejabberd_hooks:delete(webadmin_menu_main, ?MODULE, web_menu_main, 50), - ejabberd_hooks:delete(webadmin_menu_host, Host, ?MODULE, web_menu_host, 50), - ejabberd_hooks:delete(webadmin_page_main, ?MODULE, web_page_main, 50), - ejabberd_hooks:delete(webadmin_page_host, Host, ?MODULE, web_page_host, 50). - -%%% -%%% Register commands -%%% - -commands() -> - [ - #ejabberd_commands{name = muc_online_rooms, tags = [muc], - desc = "List existing rooms ('global' to get all vhosts)", - module = ?MODULE, function = muc_online_rooms, - args = [{host, binary}], - result = {rooms, {list, {room, string}}}}, - #ejabberd_commands{name = muc_unregister_nick, tags = [muc], - desc = "Unregister the nick in the MUC service", - module = ?MODULE, function = muc_unregister_nick, - args = [{nick, binary}], - result = {res, rescode}}, - - #ejabberd_commands{name = create_room, tags = [muc_room], - desc = "Create a MUC room name@service in host", - module = ?MODULE, function = create_room, - args = [{name, binary}, {service, binary}, - {host, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = destroy_room, tags = [muc_room], - desc = "Destroy a MUC room", - module = ?MODULE, function = destroy_room, - args = [{name, binary}, {service, binary}, - {host, binary}], - result = {res, rescode}}, - #ejabberd_commands{name = create_rooms_file, tags = [muc], - desc = "Create the rooms indicated in file", - module = ?MODULE, function = create_rooms_file, - args = [{file, string}], - result = {res, rescode}}, - #ejabberd_commands{name = destroy_rooms_file, tags = [muc], - desc = "Destroy the rooms indicated in file", - module = ?MODULE, function = destroy_rooms_file, - args = [{file, string}], - result = {res, rescode}}, - #ejabberd_commands{name = rooms_unused_list, tags = [muc], - desc = "List the rooms that are unused for many days in host", - module = ?MODULE, function = rooms_unused_list, - args = [{host, binary}, {days, integer}], - result = {rooms, {list, {room, string}}}}, - #ejabberd_commands{name = rooms_unused_destroy, tags = [muc], - desc = "Destroy the rooms that are unused for many days in host", - module = ?MODULE, function = rooms_unused_destroy, - args = [{host, binary}, {days, integer}], - result = {rooms, {list, {room, string}}}}, - - #ejabberd_commands{name = get_room_occupants, tags = [muc_room], - desc = "Get the list of occupants of a MUC room", - module = ?MODULE, function = get_room_occupants, - args = [{name, binary}, {service, binary}], - result = {occupants, {list, - {occupant, {tuple, - [{jid, string}, - {nick, string}, - {role, string} - ]}} - }}}, - - #ejabberd_commands{name = get_room_occupants_number, tags = [muc_room], - desc = "Get the number of occupants of a MUC room", - module = ?MODULE, function = get_room_occupants_number, - args = [{name, binary}, {service, binary}], - result = {occupants, integer}}, - - #ejabberd_commands{name = send_direct_invitation, tags = [muc_room], - desc = "Send a direct invitation to several destinations", - longdesc = "Password and Message can also be: none. Users JIDs are separated with : ", - module = ?MODULE, function = send_direct_invitation, - args = [{room, binary}, {password, binary}, {reason, binary}, {users, string}], - result = {res, rescode}}, - - #ejabberd_commands{name = change_room_option, tags = [muc_room], - desc = "Change an option in a MUC room", - module = ?MODULE, function = change_room_option, - args = [{name, binary}, {service, binary}, - {option, string}, {value, string}], - result = {res, rescode}}, - - #ejabberd_commands{name = set_room_affiliation, tags = [muc_room], - desc = "Change an affiliation in a MUC room", - module = ?MODULE, function = set_room_affiliation, - args = [{name, binary}, {service, binary}, - {jid, binary}, {affiliation, string}], - result = {res, rescode}}, - #ejabberd_commands{name = get_room_affiliations, tags = [muc_room], - desc = "Get the list of affiliations of a MUC room", - module = ?MODULE, function = get_room_affiliations, - args = [{name, binary}, {service, binary}], - result = {affiliations, {list, - {affiliation, {tuple, - [{username, string}, - {domain, string}, - {affiliation, atom}, - {reason, string} - ]}} - }}} - ]. - - -%%% -%%% ejabberd commands -%%% - -muc_online_rooms(ServerHost) -> - MUCHost = find_host(ServerHost), - Rooms = ets:tab2list(muc_online_room), - lists:foldl( - fun({_, {Roomname, Host}, _}, Results) -> - case MUCHost of - global -> - [<> | Results]; - Host -> - [<> | Results]; - _ -> - Results - end - end, - [], - Rooms). - -muc_unregister_nick(Nick) -> - F2 = fun(N) -> - [{_,Key,_}] = mnesia:index_read(muc_registered, N, 3), - mnesia:delete({muc_registered, Key}) - end, - case mnesia:transaction(F2, [Nick], 1) of - {atomic, ok} -> - ok; - {aborted, _Error} -> - error - end. - - -%%---------------------------- -%% Ad-hoc commands -%%---------------------------- - - -%%---------------------------- -%% Web Admin -%%---------------------------- - -%%--------------- -%% Web Admin Menu - -web_menu_main(Acc, Lang) -> - Acc ++ [{<<"muc">>, ?T(<<"Multi-User Chat">>)}]. - -web_menu_host(Acc, _Host, Lang) -> - Acc ++ [{<<"muc">>, ?T(<<"Multi-User Chat">>)}]. - - -%%--------------- -%% Web Admin Page - --define(TDTD(L, N), - ?XE(<<"tr">>, [?XCT(<<"td">>, L), - ?XC(<<"td">>, jlib:integer_to_binary(N)) - ])). - -web_page_main(_, #request{path=[<<"muc">>], lang = Lang} = _Request) -> - Res = [?XC(<<"h1">>, <<"Multi-User Chat">>), - ?XC(<<"h3">>, <<"Statistics">>), - ?XAE(<<"table">>, [], - [?XE(<<"tbody">>, [?TDTD(<<"Total rooms">>, ets:info(muc_online_room, size)), - ?TDTD(<<"Permanent rooms">>, mnesia:table_info(muc_room, size)), - ?TDTD(<<"Registered nicknames">>, mnesia:table_info(muc_registered, size)) - ]) - ]), - ?XE(<<"ul">>, [?LI([?ACT(<<"rooms">>, <<"List of rooms">>)])]) - ], - {stop, Res}; - -web_page_main(_, #request{path=[<<"muc">>, <<"rooms">>], q = Q, lang = Lang} = _Request) -> - Sort_query = get_sort_query(Q), - Res = make_rooms_page(global, Lang, Sort_query), - {stop, Res}; - -web_page_main(Acc, _) -> Acc. - -web_page_host(_, Host, - #request{path = [<<"muc">>], - q = Q, - lang = Lang} = _Request) -> - Sort_query = get_sort_query(Q), - Res = make_rooms_page(find_host(Host), Lang, Sort_query), - {stop, Res}; -web_page_host(Acc, _, _) -> Acc. - - -%% Returns: {normal | reverse, Integer} -get_sort_query(Q) -> - case catch get_sort_query2(Q) of - {ok, Res} -> Res; - _ -> {normal, 1} - end. - -get_sort_query2(Q) -> - {value, {_, String}} = lists:keysearch(<<"sort">>, 1, Q), - Integer = list_to_integer(String), - case Integer >= 0 of - true -> {ok, {normal, Integer}}; - false -> {ok, {reverse, abs(Integer)}} - end. - -make_rooms_page(Host, Lang, {Sort_direction, Sort_column}) -> - Rooms_names = get_rooms(Host), - Rooms_infos = build_info_rooms(Rooms_names), - Rooms_sorted = sort_rooms(Sort_direction, Sort_column, Rooms_infos), - Rooms_prepared = prepare_rooms_infos(Rooms_sorted), - TList = lists:map( - fun(Room) -> - ?XE(<<"tr">>, [?XC(<<"td">>, E) || E <- Room]) - end, Rooms_prepared), - Titles = [<<"Jabber ID">>, - <<"# participants">>, - <<"Last message">>, - <<"Public">>, - <<"Persistent">>, - <<"Logging">>, - <<"Just created">>, - <<"Title">>], - {Titles_TR, _} = - lists:mapfoldl( - fun(Title, Num_column) -> - NCS = jlib:integer_to_binary(Num_column), - TD = ?XE(<<"td">>, [?CT(Title), - ?C(<<" ">>), - ?ACT(<<"?sort=", NCS/binary>>, <<"<">>), - ?C(<<" ">>), - ?ACT(<<"?sort=-", NCS/binary>>, <<">">>)]), - {TD, Num_column+1} - end, - 1, - Titles), - [?XC(<<"h1">>, <<"Multi-User Chat">>), - ?XC(<<"h2">>, <<"Rooms">>), - ?XE(<<"table">>, - [?XE(<<"thead">>, - [?XE(<<"tr">>, Titles_TR)] - ), - ?XE(<<"tbody">>, TList) - ] - ) - ]. - -sort_rooms(Direction, Column, Rooms) -> - Rooms2 = lists:keysort(Column, Rooms), - case Direction of - normal -> Rooms2; - reverse -> lists:reverse(Rooms2) - end. - -build_info_rooms(Rooms) -> - [build_info_room(Room) || Room <- Rooms]. - -build_info_room({Name, Host, Pid}) -> - C = get_room_config(Pid), - Title = C#config.title, - Public = C#config.public, - Persistent = C#config.persistent, - Logging = C#config.logging, - - S = get_room_state(Pid), - Just_created = S#state.just_created, - Num_participants = length(dict:fetch_keys(S#state.users)), - - History = (S#state.history)#lqueue.queue, - Ts_last_message = - case queue:is_empty(History) of - true -> - <<"A long time ago">>; - false -> - Last_message1 = queue:last(History), - {_, _, _, Ts_last, _} = Last_message1, - jlib:timestamp_to_iso(Ts_last) - end, - - {<>, - Num_participants, - Ts_last_message, - Public, - Persistent, - Logging, - Just_created, - Title}. - -prepare_rooms_infos(Rooms) -> - [prepare_room_info(Room) || Room <- Rooms]. -prepare_room_info(Room_info) -> - {NameHost, - Num_participants, - Ts_last_message, - Public, - Persistent, - Logging, - Just_created, - Title} = Room_info, - [NameHost, - jlib:integer_to_binary(Num_participants), - Ts_last_message, - jlib:atom_to_binary(Public), - jlib:atom_to_binary(Persistent), - jlib:atom_to_binary(Logging), - jlib:atom_to_binary(Just_created), - Title]. - - -%%---------------------------- -%% Create/Delete Room -%%---------------------------- - -%% @spec (Name::binary(), Host::binary(), ServerHost::binary()) -> -%% ok | error -%% @doc Create a room immediately with the default options. -create_room(Name, Host, ServerHost) -> - - %% Get the default room options from the muc configuration - DefRoomOpts = gen_mod:get_module_opt(ServerHost, mod_muc, - default_room_options, fun(X) -> X end, []), - - %% Store the room on the server, it is not started yet though at this point - mod_muc:store_room(ServerHost, Host, Name, DefRoomOpts), - - %% Get all remaining mod_muc parameters that might be utilized - Access = gen_mod:get_module_opt(ServerHost, mod_muc, access, fun(X) -> X end, all), - AcCreate = gen_mod:get_module_opt(ServerHost, mod_muc, access_create, fun(X) -> X end, all), - AcAdmin = gen_mod:get_module_opt(ServerHost, mod_muc, access_admin, fun(X) -> X end, none), - AcPer = gen_mod:get_module_opt(ServerHost, mod_muc, access_persistent, fun(X) -> X end, all), - _PersistHistory = gen_mod:get_module_opt(ServerHost, mod_muc, persist_history, fun(X) -> X end, false), - HistorySize = gen_mod:get_module_opt(ServerHost, mod_muc, history_size, fun(X) -> X end, 20), - RoomShaper = gen_mod:get_module_opt(ServerHost, mod_muc, room_shaper, fun(X) -> X end, none), - - %% If the room does not exist yet in the muc_online_room - case mnesia:dirty_read(muc_online_room, {Name, Host}) of - [] -> - %% Start the room - {ok, Pid} = mod_muc_room:start( - Host, - ServerHost, - {Access, AcCreate, AcAdmin, AcPer}, - Name, - HistorySize, - RoomShaper, - DefRoomOpts), - {atomic, ok} = register_room(Host, Name, Pid), - ok; - _ -> - error - end. - -register_room(Host, Name, Pid) -> - F = fun() -> - mnesia:write(#muc_online_room{name_host = {Name, Host}, - pid = Pid}) - end, - mnesia:transaction(F). - -%% Create the room only in the database. -%% It is required to restart the MUC service for the room to appear. -muc_create_room(ServerHost, {Name, Host, _}, DefRoomOpts) -> - io:format("Creating room ~s@~s~n", [Name, Host]), - mod_muc:store_room(ServerHost, Host, Name, DefRoomOpts). - -%% @spec (Name::binary(), Host::binary(), ServerHost::binary()) -> -%% ok | {error, room_not_exists} -%% @doc Destroy the room immediately. -%% If the room has participants, they are not notified that the room was destroyed; -%% they will notice when they try to chat and receive an error that the room doesn't exist. -destroy_room(Name, Service, _Server) -> - case mnesia:dirty_read(muc_online_room, {Name, Service}) of - [R] -> - Pid = R#muc_online_room.pid, - gen_fsm:send_all_state_event(Pid, destroy), - ok; - [] -> - error - end. - -destroy_room({N, H, SH}) -> - io:format("Destroying room: ~s@~s - vhost: ~s~n", [N, H, SH]), - destroy_room(N, H, SH). - - -%%---------------------------- -%% Destroy Rooms in File -%%---------------------------- - -%% The format of the file is: one chatroom JID per line -%% The file encoding must be UTF-8 - -destroy_rooms_file(Filename) -> - {ok, F} = file:open(Filename, [read]), - RJID = read_room(F), - Rooms = read_rooms(F, RJID, []), - file:close(F), - [destroy_room(A) || A <- Rooms], - ok. - -read_rooms(_F, eof, L) -> - L; - -read_rooms(F, RJID, L) -> - RJID2 = read_room(F), - read_rooms(F, RJID2, [RJID | L]). - -read_room(F) -> - case io:get_line(F, "") of - eof -> eof; - String -> - case io_lib:fread("~s", String) of - {ok, [RoomJID], _} -> split_roomjid(RoomJID); - {error, What} -> - io:format("Parse error: what: ~p~non the line: ~p~n~n", [What, String]) - end - end. - -%% This function is quite rudimentary -%% and may not be accurate -split_roomjid(RoomJID) -> - [Name, Host] = string:tokens(RoomJID, "@"), - [_MUC_service_name | ServerHostList] = string:tokens(Host, "."), - ServerHost = join(ServerHostList, "."), - {Name, Host, ServerHost}. - -%% This function is copied from string:join/2 in Erlang/OTP R12B-1 -%% Note that string:join/2 is not implemented in Erlang/OTP R11B -join([H|T], Sep) -> - H ++ lists:concat([Sep ++ X || X <- T]). - - -%%---------------------------- -%% Create Rooms in File -%%---------------------------- - -create_rooms_file(Filename) -> - {ok, F} = file:open(Filename, [read]), - RJID = read_room(F), - Rooms = read_rooms(F, RJID, []), - file:close(F), - %% Read the default room options defined for the first virtual host - DefRoomOpts = gen_mod:get_module_opt(?MYNAME, mod_muc, - default_room_options, []), - [muc_create_room(?MYNAME, A, DefRoomOpts) || A <- Rooms], - ok. - - -%%---------------------------- -%% List/Delete Unused Rooms -%%---------------------------- - -%%--------------- -%% Control - -rooms_unused_list(Host, Days) -> - rooms_unused_report(list, Host, Days). -rooms_unused_destroy(Host, Days) -> - rooms_unused_report(destroy, Host, Days). - -rooms_unused_report(Action, Host, Days) -> - {NA, NP, RP} = muc_unused(Action, Host, Days), - io:format("Unused rooms: ~p out of ~p~n", [NP, NA]), - [[R, <<"@">>, H] || {R, H, _P} <- RP]. - -muc_unused(Action, ServerHost, Days) -> - Host = find_host(ServerHost), - muc_unused2(Action, ServerHost, Host, Days). - -muc_unused2(Action, ServerHost, Host, Last_allowed) -> - %% Get all required info about all existing rooms - Rooms_all = get_rooms(Host), - - %% Decide which ones pass the requirements - Rooms_pass = decide_rooms(Rooms_all, Last_allowed), - - Num_rooms_all = length(Rooms_all), - Num_rooms_pass = length(Rooms_pass), - - %% Perform the desired action for matching rooms - act_on_rooms(Action, Rooms_pass, ServerHost), - - {Num_rooms_all, Num_rooms_pass, Rooms_pass}. - -%%--------------- -%% Get info - -get_rooms(Host) -> - Get_room_names = fun(Room_reg, Names) -> - Pid = Room_reg#muc_online_room.pid, - case {Host, Room_reg#muc_online_room.name_host} of - {Host, {Name1, Host}} -> - [{Name1, Host, Pid} | Names]; - {global, {Name1, Host1}} -> - [{Name1, Host1, Pid} | Names]; - _ -> - Names - end - end, - ets:foldr(Get_room_names, [], muc_online_room). - -get_room_config(Room_pid) -> - {ok, R} = gen_fsm:sync_send_all_state_event(Room_pid, get_config), - R. - -get_room_state(Room_pid) -> - {ok, R} = gen_fsm:sync_send_all_state_event(Room_pid, get_state), - R. - -%%--------------- -%% Decide - -decide_rooms(Rooms, Last_allowed) -> - Decide = fun(R) -> decide_room(R, Last_allowed) end, - lists:filter(Decide, Rooms). - -decide_room({_Room_name, _Host, Room_pid}, Last_allowed) -> - C = get_room_config(Room_pid), - Persistent = C#config.persistent, - - S = get_room_state(Room_pid), - Just_created = S#state.just_created, - - Room_users = S#state.users, - Num_users = length(?DICT:to_list(Room_users)), - - History = (S#state.history)#lqueue.queue, - Ts_now = calendar:now_to_universal_time(now()), - Ts_uptime = uptime_seconds(), - {Has_hist, Last} = case queue:is_empty(History) of - true -> - {false, Ts_uptime}; - false -> - Last_message = queue:last(History), - {_, _, _, Ts_last, _} = Last_message, - Ts_diff = - calendar:datetime_to_gregorian_seconds(Ts_now) - - calendar:datetime_to_gregorian_seconds(Ts_last), - {true, Ts_diff} - end, - - case {Persistent, Just_created, Num_users, Has_hist, seconds_to_days(Last)} of - {_true, false, 0, _, Last_days} - when Last_days >= Last_allowed -> - true; - _ -> - false - end. - -seconds_to_days(S) -> - S div (60*60*24). - -%%--------------- -%% Act - -act_on_rooms(Action, Rooms, ServerHost) -> - ServerHosts = [ {A, find_host(A)} || A <- ?MYHOSTS ], - Delete = fun({_N, H, _Pid} = Room) -> - SH = case ServerHost of - global -> find_serverhost(H, ServerHosts); - O -> O - end, - - act_on_room(Action, Room, SH) - end, - lists:foreach(Delete, Rooms). - -find_serverhost(Host, ServerHosts) -> - {value, {ServerHost, Host}} = lists:keysearch(Host, 2, ServerHosts), - ServerHost. - -act_on_room(destroy, {N, H, Pid}, SH) -> - gen_fsm:send_all_state_event( - Pid, {destroy, <<"Room destroyed by rooms_unused_destroy.">>}), - mod_muc:room_destroyed(H, N, Pid, SH), - mod_muc:forget_room(SH, H, N); - -act_on_room(list, _, _) -> - ok. - - -%%---------------------------- -%% Change Room Option -%%---------------------------- - -get_room_occupants(Room, Host) -> - case get_room_pid(Room, Host) of - room_not_found -> throw({error, room_not_found}); - Pid -> get_room_occupants(Pid) - end. - -get_room_occupants(Pid) -> - S = get_room_state(Pid), - lists:map( - fun({_LJID, Info}) -> - {jlib:jid_to_string(Info#user.jid), - Info#user.nick, - atom_to_list(Info#user.role)} - end, - dict:to_list(S#state.users)). - -get_room_occupants_number(Room, Host) -> - length(get_room_occupants(Room, Host)). - -%%---------------------------- -%% Send Direct Invitation -%%---------------------------- -%% http://xmpp.org/extensions/xep-0249.html - -send_direct_invitation(RoomString, Password, Reason, UsersString) -> - RoomJid = jlib:string_to_jid(RoomString), - XmlEl = build_invitation(Password, Reason, RoomString), - UsersStrings = get_users_to_invite(RoomJid, UsersString), - [send_direct_invitation(RoomJid, jlib:string_to_jid(list_to_binary(UserStrings)), XmlEl) - || UserStrings <- UsersStrings], - timer:sleep(1000), - ok. - -get_users_to_invite(RoomJid, UsersString) -> - UsersStrings = string:tokens(UsersString, ":"), - OccupantsTuples = get_room_occupants(RoomJid#jid.luser, - RoomJid#jid.lserver), - OccupantsJids = [jlib:string_to_jid(JidString) - || {JidString, _Nick, _} <- OccupantsTuples], - lists:filter( - fun(UserString) -> - UserJid = jlib:string_to_jid(list_to_binary(UserString)), - %% [{"badlop@localhost/work","badlop","moderator"}] - lists:all(fun(OccupantJid) -> - UserJid#jid.luser /= OccupantJid#jid.luser - orelse UserJid#jid.lserver /= OccupantJid#jid.lserver - end, - OccupantsJids) - end, - UsersStrings). - -build_invitation(Password, Reason, RoomString) -> - PasswordAttrList = case Password of - <<"none">> -> []; - _ -> [{<<"password">>, Password}] - end, - ReasonAttrList = case Reason of - <<"none">> -> []; - _ -> [{<<"reason">>, Reason}] - end, - XAttrs = [{<<"xmlns">>, ?NS_XCONFERENCE}, - {<<"jid">>, RoomString}] - ++ PasswordAttrList - ++ ReasonAttrList, - XEl = {xmlel, <<"x">>, XAttrs, []}, - {xmlel, <<"message">>, [], [XEl]}. - -send_direct_invitation(FromJid, UserJid, XmlEl) -> - ejabberd_router:route(FromJid, UserJid, XmlEl). - -%%---------------------------- -%% Change Room Option -%%---------------------------- - -%% @spec(Name::string(), Service::string(), Option::string(), Value) -> ok -%% Value = atom() | integer() | string() -%% @doc Change an option in an existing room. -%% Requires the name of the room, the MUC service where it exists, -%% the option to change (for example title or max_users), -%% and the value to assign to the new option. -%% For example: -%% change_room_option("testroom", "conference.localhost", "title", "Test Room") -change_room_option(Name, Service, Option, Value) when is_atom(Option) -> - Pid = get_room_pid(Name, Service), - {ok, _} = change_room_option(Pid, Option, Value), - ok; -change_room_option(Name, Service, OptionString, ValueString) -> - Option = list_to_atom(OptionString), - Value = case Option of - title -> ValueString; - description -> ValueString; - password -> ValueString; - max_users -> list_to_integer(ValueString); - _ -> list_to_atom(ValueString) - end, - change_room_option(Name, Service, Option, Value). - -change_room_option(Pid, Option, Value) -> - Config = get_room_config(Pid), - Config2 = change_option(Option, Value, Config), - gen_fsm:sync_send_all_state_event(Pid, {change_config, Config2}). - -%% @doc Get the Pid of an existing MUC room, or 'room_not_found'. -get_room_pid(Name, Service) -> - case mnesia:dirty_read(muc_online_room, {Name, Service}) of - [] -> - room_not_found; - [Room] -> - Room#muc_online_room.pid - end. - -%% It is required to put explicitely all the options because -%% the record elements are replaced at compile time. -%% So, this can't be parametrized. -change_option(Option, Value, Config) -> - case Option of - allow_change_subj -> Config#config{allow_change_subj = Value}; - allow_private_messages -> Config#config{allow_private_messages = Value}; - allow_query_users -> Config#config{allow_query_users = Value}; - allow_user_invites -> Config#config{allow_user_invites = Value}; - anonymous -> Config#config{anonymous = Value}; - logging -> Config#config{logging = Value}; - max_users -> Config#config{max_users = Value}; - members_by_default -> Config#config{members_by_default = Value}; - members_only -> Config#config{members_only = Value}; - moderated -> Config#config{moderated = Value}; - password -> Config#config{password = Value}; - password_protected -> Config#config{password_protected = Value}; - persistent -> Config#config{persistent = Value}; - public -> Config#config{public = Value}; - public_list -> Config#config{public_list = Value}; - title -> Config#config{title = Value} - end. - - -%%---------------------------- -%% Get Room Affiliations -%%---------------------------- - -%% @spec(Name::binary(), Service::binary()) -> -%% [{JID::string(), Domain::string(), Role::string(), Reason::string()}] -%% @doc Get the affiliations of the room Name@Service. -get_room_affiliations(Name, Service) -> - case mnesia:dirty_read(muc_online_room, {Name, Service}) of - [R] -> - %% Get the PID of the online room, then request its state - Pid = R#muc_online_room.pid, - {ok, StateData} = gen_fsm:sync_send_all_state_event(Pid, get_state), - Affiliations = ?DICT:to_list(StateData#state.affiliations), - lists:map( - fun({{Uname, Domain, _Res}, {Aff, Reason}}) when is_atom(Aff)-> - {Uname, Domain, Aff, Reason}; - ({{Uname, Domain, _Res}, Aff}) when is_atom(Aff)-> - {Uname, Domain, Aff, <<>>} - end, Affiliations); - [] -> - throw({error, "The room does not exist."}) - end. - -%%---------------------------- -%% Change Room Affiliation -%%---------------------------- - -%% @spec(Name, Service, JID, AffiliationString) -> ok | {error, Error} -%% Name = binary() -%% Service = binary() -%% JID = binary() -%% AffiliationString = "outcast" | "none" | "member" | "admin" | "owner" -%% @doc Set the affiliation of JID in the room Name@Service. -%% If the affiliation is 'none', the action is to remove, -%% In any other case the action will be to create the affiliation. -set_room_affiliation(Name, Service, JID, AffiliationString) -> - Affiliation = list_to_atom(AffiliationString), - case mnesia:dirty_read(muc_online_room, {Name, Service}) of - [R] -> - %% Get the PID for the online room so we can get the state of the room - Pid = R#muc_online_room.pid, - {ok, StateData} = gen_fsm:sync_send_all_state_event(Pid, {process_item_change, {jlib:string_to_jid(JID), affiliation, Affiliation, <<"">>}, <<"">>}), - mod_muc:store_room(StateData#state.server_host, StateData#state.host, StateData#state.room, make_opts(StateData)), - ok; - [] -> - error - end. - --define(MAKE_CONFIG_OPT(Opt), {Opt, Config#config.Opt}). - -make_opts(StateData) -> - Config = StateData#state.config, - [ - ?MAKE_CONFIG_OPT(title), - ?MAKE_CONFIG_OPT(allow_change_subj), - ?MAKE_CONFIG_OPT(allow_query_users), - ?MAKE_CONFIG_OPT(allow_private_messages), - ?MAKE_CONFIG_OPT(public), - ?MAKE_CONFIG_OPT(public_list), - ?MAKE_CONFIG_OPT(persistent), - ?MAKE_CONFIG_OPT(moderated), - ?MAKE_CONFIG_OPT(members_by_default), - ?MAKE_CONFIG_OPT(members_only), - ?MAKE_CONFIG_OPT(allow_user_invites), - ?MAKE_CONFIG_OPT(password_protected), - ?MAKE_CONFIG_OPT(password), - ?MAKE_CONFIG_OPT(anonymous), - ?MAKE_CONFIG_OPT(logging), - ?MAKE_CONFIG_OPT(max_users), - {affiliations, ?DICT:to_list(StateData#state.affiliations)}, - {subject, StateData#state.subject}, - {subject_author, StateData#state.subject_author} - ]. - - -%%---------------------------- -%% Utils -%%---------------------------- - -uptime_seconds() -> - trunc(element(1, erlang:statistics(wall_clock))/1000). - -find_host(global) -> - global; -find_host("global") -> - global; -find_host(<<"global">>) -> - global; -find_host(ServerHost) when is_list(ServerHost) -> - find_host(list_to_binary(ServerHost)); -find_host(ServerHost) -> - gen_mod:get_module_opt_host(ServerHost, mod_muc, <<"conference.@HOST@">>). -