Cleanup for module packaging support in ejabberd
This commit is contained in:
parent
af33df5594
commit
4c68f4421b
|
@ -2,9 +2,8 @@ This is the list of modules that are known to be broken with latest ejabberd mas
|
||||||
|
|
||||||
If you feel they are worth it, your help to fix them is welcome:
|
If you feel they are worth it, your help to fix them is welcome:
|
||||||
|
|
||||||
- atom_pubsub: "The atom_pubsub module provides access to all PEP nodes via an
|
- atom_pubsub: "Provides access to all PEP nodes via an AtomPub interface."
|
||||||
AtomPub interface."
|
|
||||||
- ircd: "This is an IRC server frontend to ejabberd."
|
- ircd: "This is an IRC server frontend to ejabberd."
|
||||||
- mod_archive: "Message Archiving (XEP-0136)"
|
- mod_archive: "Message Archiving (XEP-0136)."
|
||||||
- mod_openid: "Transform the Jabber Server in an openid provider."
|
- mod_openid: "Transform the Jabber Server in an openid provider."
|
||||||
- mod_profile: "User Profile (XEP-0154) in Mnesia table"
|
- mod_profile: "User Profile (XEP-0154) in Mnesia table."
|
||||||
|
|
54
README.md
54
README.md
|
@ -10,52 +10,38 @@ For users
|
||||||
|
|
||||||
To use an ejabberd module coming from this repository:
|
To use an ejabberd module coming from this repository:
|
||||||
|
|
||||||
- You need to have Erlang installed.
|
- You need to have Ejabberd installed.
|
||||||
|
|
||||||
- Read the module-specific `README.txt` file to see if special steps are
|
- Run `ejabberdctl install <module>` to get the sources, compile and install
|
||||||
required to deploy it.
|
the beams file in ejabberd path. This path is either ~/.ejabberd-modules or
|
||||||
|
defined by CONTRIB\_MODULES\_PATH in ejabberdctl.cfg.
|
||||||
|
|
||||||
- Run `./build.sh` or `build.bat` in the root directory of the desired
|
- Edit the configuration file provided in the `conf` dir of the installed
|
||||||
module.
|
module to update to your needs. Then apply the changes to your main ejabberd
|
||||||
|
configuration. On future release, ejabberd will automatically add this file
|
||||||
- Copy generated `.beam` files from the `ebin` directory to the directory
|
to its runtime configuration without changes.
|
||||||
where your ejabberd `.beam` files are.
|
|
||||||
|
|
||||||
- Use the configuration file examples provided in the `conf` dir to update
|
|
||||||
your `ejabberd.cfg` or `ejabberd.yml` configuration file.
|
|
||||||
|
|
||||||
If during compilation of a module you get an error like:
|
|
||||||
|
|
||||||
{"init terminating in do_boot",{undef,[{make,all,[]},...
|
|
||||||
|
|
||||||
it means Erlang couldn't find its `make.beam` file. In Debian and other
|
|
||||||
distributions you can try to install packages like:
|
|
||||||
|
|
||||||
erlang-dev erlang-nox erlang-tools
|
|
||||||
|
|
||||||
|
- Run `ejabberdctl uninstall <module>` to remove a module from your ejabberd.
|
||||||
|
|
||||||
For developers
|
For developers
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
The following organization has been set up for the development:
|
The following organization has been set up for the development:
|
||||||
|
|
||||||
- Development and compilation of modules should be possible without the
|
- Development and compilation of modules is done by ejabberd. You need
|
||||||
ejabberd source code, as the `ejabberd-dev` helper module contains the
|
Ejabberd installed. Use `ejabberdctl check_module <module>` to ensure
|
||||||
include files necessary to make compilation possible.
|
it compiles correctly before commit your work. Sources of your module
|
||||||
|
must be located in $CONTRIB\_MODULES\_PATH/sources/<module>
|
||||||
|
|
||||||
- The module directory structure is usually the following:
|
- The module directory structure is usually the following:
|
||||||
* `README.txt`: Module description.
|
* `README.txt`: Module description.
|
||||||
* `LICENSE.txt`: License for the module.
|
* `COPYING`: License for the module.
|
||||||
* `Emakefile`: Erlang Makefile to build the module (preferred way, if
|
|
||||||
no dependencies on C code, as build will thus work on Windows).
|
|
||||||
* `doc/`: Documentation directory.
|
* `doc/`: Documentation directory.
|
||||||
* `src/`: Source directory.
|
* `src/`: Erlang source directory.
|
||||||
* `src/msgs/`: Directory with translation files (pot, po and msg).
|
* `lib/`: Elixir source directory.
|
||||||
* `ebin/`: Empty (target directory for the build).
|
* `priv/msgs/`: Directory with translation files (pot, po and msg).
|
||||||
* `conf/`: Directory containing example configuration for your module.
|
* `conf/<module>.yml`: Configuration for your module.
|
||||||
* `build.sh`: Unix/Linux build script.
|
* `<module>.spec`: Yaml description file for your module.
|
||||||
* `build.bat`: Windows build script.
|
|
||||||
|
|
||||||
- Module developers should note in the `README.txt` file whether the
|
- Module developers should note in the `README.txt` file whether the
|
||||||
module has requirements or known incompatibilities with other modules
|
module has requirements or known incompatibilities with other modules.
|
||||||
(for example, by modifying the same main ejabberd modules).
|
|
||||||
|
|
|
@ -0,0 +1,342 @@
|
||||||
|
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 Lesser 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.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 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 Lesser General
|
||||||
|
Public License instead of this License.
|
|
@ -1,4 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/atom_microblog', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/atom_pubsub', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_couch', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -23,28 +23,6 @@ http://www.cestari.info/2008/6/19/atom-pubsub-module-for-ejabberd
|
||||||
http://www.cestari.info/2008/9/12/atom_pubsub-dead-long-live-atom_microblog
|
http://www.cestari.info/2008/9/12/atom_pubsub-dead-long-live-atom_microblog
|
||||||
|
|
||||||
|
|
||||||
INSTALL
|
|
||||||
-------
|
|
||||||
|
|
||||||
1. Compile the files executing: ./build.sh
|
|
||||||
|
|
||||||
2. Copy beam files from ebin/ into your ejabberd installation.
|
|
||||||
|
|
||||||
3. Edit ejabberd.cfg and add a request handler in ejabberd_http listener:
|
|
||||||
{listen, [
|
|
||||||
...
|
|
||||||
{8080, ejabberd_http, [
|
|
||||||
http_poll,
|
|
||||||
web_admin,
|
|
||||||
{request_handlers, [{["pep"], atom_microblog}, % Make sure it's "pep", or change it in atom_microblog.erl
|
|
||||||
{["pubsub"], atom_pubsub}]} % Make sure it's "pubsub", or change it in atom_pubsub.erl
|
|
||||||
|
|
||||||
]}
|
|
||||||
]}.
|
|
||||||
|
|
||||||
4. Restart ejabberd.
|
|
||||||
|
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Eric Cestari <eric at ohmforce.com>"
|
||||||
|
category: "pubsub"
|
||||||
|
summary: "Provides access to all PEP nodes via an AtomPub interface"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/atom_pubsub"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
listen:
|
||||||
|
-
|
||||||
|
port: 8080
|
||||||
|
module: ejabberd_http
|
||||||
|
request_handlers:
|
||||||
|
"pep": atom_microblog
|
||||||
|
"pubsub": atom_pubsub
|
|
@ -1,5 +0,0 @@
|
||||||
ejabberd-dev is an helper module containing include files from the ejabberd
|
|
||||||
project.
|
|
||||||
|
|
||||||
This should allow to develop or build ejabberd modules without a complete
|
|
||||||
development version of ejabberd (for example with a binary version of ejabberd).
|
|
|
@ -1,44 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-record(adhoc_request,
|
|
||||||
{
|
|
||||||
lang = <<"">> :: binary(),
|
|
||||||
node = <<"">> :: binary(),
|
|
||||||
sessionid = <<"">> :: binary(),
|
|
||||||
action = <<"">> :: binary(),
|
|
||||||
xdata = false :: false | xmlel(),
|
|
||||||
others = [] :: [xmlel()]
|
|
||||||
}).
|
|
||||||
|
|
||||||
-record(adhoc_response,
|
|
||||||
{
|
|
||||||
lang = <<"">> :: binary(),
|
|
||||||
node = <<"">> :: binary(),
|
|
||||||
sessionid = <<"">> :: binary(),
|
|
||||||
status :: atom(),
|
|
||||||
defaultaction = <<"">> :: binary(),
|
|
||||||
actions = [] :: [binary()],
|
|
||||||
notes = [] :: [{binary(), binary()}],
|
|
||||||
elements = [] :: [xmlel()]
|
|
||||||
}).
|
|
||||||
|
|
||||||
-type adhoc_request() :: #adhoc_request{}.
|
|
||||||
-type adhoc_response() :: #adhoc_response{}.
|
|
|
@ -1,51 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
%% This macro returns a string of the ejabberd version running, e.g. "2.3.4"
|
|
||||||
%% If the ejabberd application description isn't loaded, returns atom: undefined
|
|
||||||
-define(VERSION, ejabberd_config:get_version()).
|
|
||||||
|
|
||||||
-define(MYHOSTS, ejabberd_config:get_myhosts()).
|
|
||||||
|
|
||||||
-define(MYNAME, hd(ejabberd_config:get_myhosts())).
|
|
||||||
|
|
||||||
-define(MYLANG, ejabberd_config:get_mylang()).
|
|
||||||
|
|
||||||
-define(MSGS_DIR, filename:join(["priv", "msgs"])).
|
|
||||||
|
|
||||||
-define(CONFIG_PATH, <<"ejabberd.cfg">>).
|
|
||||||
|
|
||||||
-define(LOG_PATH, <<"ejabberd.log">>).
|
|
||||||
|
|
||||||
-define(EJABBERD_URI, <<"http://www.process-one.net/en/ejabberd/">>).
|
|
||||||
|
|
||||||
-define(S2STIMEOUT, 600000).
|
|
||||||
|
|
||||||
%%-define(DBGFSM, true).
|
|
||||||
|
|
||||||
-record(scram,
|
|
||||||
{storedkey = <<"">>,
|
|
||||||
serverkey = <<"">>,
|
|
||||||
salt = <<"">>,
|
|
||||||
iterationcount = 0 :: integer()}).
|
|
||||||
|
|
||||||
-type scram() :: #scram{}.
|
|
||||||
|
|
||||||
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
|
|
|
@ -1,74 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-type aterm() :: {atom(), atype()}.
|
|
||||||
-type atype() :: integer | string | binary |
|
|
||||||
{tuple, [aterm()]} | {list, aterm()}.
|
|
||||||
-type rterm() :: {atom(), rtype()}.
|
|
||||||
-type rtype() :: integer | string | atom |
|
|
||||||
{tuple, [rterm()]} | {list, rterm()} |
|
|
||||||
rescode | restuple.
|
|
||||||
|
|
||||||
-record(ejabberd_commands,
|
|
||||||
{name :: atom(),
|
|
||||||
tags = [] :: [atom()] | '_' | '$2',
|
|
||||||
desc = "" :: string() | '_' | '$3',
|
|
||||||
longdesc = "" :: string() | '_',
|
|
||||||
module :: atom(),
|
|
||||||
function :: atom(),
|
|
||||||
args = [] :: [aterm()] | '_' | '$1' | '$2',
|
|
||||||
result = {res, rescode} :: rterm() | '_' | '$2'}).
|
|
||||||
|
|
||||||
-type ejabberd_commands() :: #ejabberd_commands{name :: atom(),
|
|
||||||
tags :: [atom()],
|
|
||||||
desc :: string(),
|
|
||||||
longdesc :: string(),
|
|
||||||
module :: atom(),
|
|
||||||
function :: atom(),
|
|
||||||
args :: [aterm()],
|
|
||||||
result :: rterm()}.
|
|
||||||
|
|
||||||
%% @type ejabberd_commands() = #ejabberd_commands{
|
|
||||||
%% name = atom(),
|
|
||||||
%% tags = [atom()],
|
|
||||||
%% desc = string(),
|
|
||||||
%% longdesc = string(),
|
|
||||||
%% module = atom(),
|
|
||||||
%% function = atom(),
|
|
||||||
%% args = [aterm()],
|
|
||||||
%% result = rterm()
|
|
||||||
%% }.
|
|
||||||
%% desc: Description of the command
|
|
||||||
%% args: Describe the accepted arguments.
|
|
||||||
%% This way the function that calls the command can format the
|
|
||||||
%% arguments before calling.
|
|
||||||
|
|
||||||
%% @type atype() = integer | string | {tuple, [aterm()]} | {list, aterm()}.
|
|
||||||
%% Allowed types for arguments are integer, string, tuple and list.
|
|
||||||
|
|
||||||
%% @type rtype() = integer | string | atom | {tuple, [rterm()]} | {list, rterm()} | rescode | restuple.
|
|
||||||
%% A rtype is either an atom or a tuple with two elements.
|
|
||||||
|
|
||||||
%% @type aterm() = {Name::atom(), Type::atype()}.
|
|
||||||
%% An argument term is a tuple with the term name and the term type.
|
|
||||||
|
|
||||||
%% @type rterm() = {Name::atom(), Type::rtype()}.
|
|
||||||
%% A result term is a tuple with the term name and the term type.
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-record(local_config, {key :: any(), value :: any()}).
|
|
||||||
|
|
||||||
-type local_config() :: #local_config{}.
|
|
||||||
|
|
||||||
-record(state,
|
|
||||||
{opts = [] :: [acl:acl() | local_config()],
|
|
||||||
hosts = [] :: [binary()],
|
|
||||||
override_local = false :: boolean(),
|
|
||||||
override_global = false :: boolean(),
|
|
||||||
override_acls = false :: boolean()}).
|
|
|
@ -1,27 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-define(STATUS_SUCCESS, 0).
|
|
||||||
|
|
||||||
-define(STATUS_ERROR, 1).
|
|
||||||
|
|
||||||
-define(STATUS_USAGE, 2).
|
|
||||||
|
|
||||||
-define(STATUS_BADRPC, 3).
|
|
|
@ -1,36 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-record(request,
|
|
||||||
{method, % :: method(),
|
|
||||||
path = [] :: [binary()],
|
|
||||||
q = [] :: [{binary() | nokey, binary()}],
|
|
||||||
us = {<<>>, <<>>} :: {binary(), binary()},
|
|
||||||
auth :: {binary(), binary()} |
|
|
||||||
{auth_jid, {binary(), binary()}, jlib:jid()},
|
|
||||||
lang = <<"">> :: binary(),
|
|
||||||
data = <<"">> :: binary(),
|
|
||||||
ip :: {inet:ip_address(), inet:port_number()},
|
|
||||||
host = <<"">> :: binary(),
|
|
||||||
port = 5280 :: inet:port_number(),
|
|
||||||
tp = http, % :: protocol(),
|
|
||||||
opts = [] :: list(),
|
|
||||||
headers = [] :: [{atom() | binary(), binary()}]}).
|
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-define(X(Name),
|
|
||||||
#xmlel{name = Name, attrs = [], children = []}).
|
|
||||||
|
|
||||||
-define(XA(Name, Attrs),
|
|
||||||
#xmlel{name = Name, attrs = Attrs, children = []}).
|
|
||||||
|
|
||||||
-define(XE(Name, Els),
|
|
||||||
#xmlel{name = Name, attrs = [], children = Els}).
|
|
||||||
|
|
||||||
-define(XAE(Name, Attrs, Els),
|
|
||||||
#xmlel{name = Name, attrs = Attrs, children = Els}).
|
|
||||||
|
|
||||||
-define(C(Text), {xmlcdata, Text}).
|
|
||||||
|
|
||||||
-define(XC(Name, Text), ?XE(Name, [?C(Text)])).
|
|
||||||
|
|
||||||
-define(XAC(Name, Attrs, Text),
|
|
||||||
?XAE(Name, Attrs, [?C(Text)])).
|
|
||||||
|
|
||||||
-define(T(Text), translate:translate(Lang, Text)).
|
|
||||||
|
|
||||||
-define(CT(Text), ?C((?T(Text)))).
|
|
||||||
|
|
||||||
-define(XCT(Name, Text), ?XC(Name, (?T(Text)))).
|
|
||||||
|
|
||||||
-define(XACT(Name, Attrs, Text),
|
|
||||||
?XAC(Name, Attrs, (?T(Text)))).
|
|
||||||
|
|
||||||
-define(LI(Els), ?XE(<<"li">>, Els)).
|
|
||||||
|
|
||||||
-define(A(URL, Els),
|
|
||||||
?XAE(<<"a">>, [{<<"href">>, URL}], Els)).
|
|
||||||
|
|
||||||
-define(AC(URL, Text), ?A(URL, [?C(Text)])).
|
|
||||||
|
|
||||||
-define(ACT(URL, Text), ?AC(URL, (?T(Text)))).
|
|
||||||
|
|
||||||
-define(P, ?X(<<"p">>)).
|
|
||||||
|
|
||||||
-define(BR, ?X(<<"br">>)).
|
|
||||||
|
|
||||||
-define(INPUT(Type, Name, Value),
|
|
||||||
?XA(<<"input">>,
|
|
||||||
[{<<"type">>, Type}, {<<"name">>, Name},
|
|
||||||
{<<"value">>, Value}])).
|
|
||||||
|
|
||||||
-define(INPUTT(Type, Name, Value),
|
|
||||||
?INPUT(Type, Name, (?T(Value)))).
|
|
||||||
|
|
||||||
-define(INPUTS(Type, Name, Value, Size),
|
|
||||||
?XA(<<"input">>,
|
|
||||||
[{<<"type">>, Type}, {<<"name">>, Name},
|
|
||||||
{<<"value">>, Value}, {<<"size">>, Size}])).
|
|
||||||
|
|
||||||
-define(INPUTST(Type, Name, Value, Size),
|
|
||||||
?INPUT(Type, Name, (?T(Value)), Size)).
|
|
||||||
|
|
||||||
-define(ACLINPUT(Text),
|
|
||||||
?XE(<<"td">>,
|
|
||||||
[?INPUT(<<"text">>, <<"value", ID/binary>>, Text)])).
|
|
||||||
|
|
||||||
-define(TEXTAREA(Name, Rows, Cols, Value),
|
|
||||||
?XAC(<<"textarea">>,
|
|
||||||
[{<<"name">>, Name}, {<<"rows">>, Rows},
|
|
||||||
{<<"cols">>, Cols}],
|
|
||||||
Value)).
|
|
||||||
|
|
||||||
%% Build an xmlelement for result
|
|
||||||
-define(XRES(Text),
|
|
||||||
?XAC(<<"p">>, [{<<"class">>, <<"result">>}], Text)).
|
|
||||||
|
|
||||||
%% Guide Link
|
|
||||||
-define(XREST(Text), ?XRES((?T(Text)))).
|
|
||||||
|
|
||||||
-define(GL(Ref, Title),
|
|
||||||
?XAE(<<"div">>, [{<<"class">>, <<"guidelink">>}],
|
|
||||||
[?XAE(<<"a">>,
|
|
||||||
[{<<"href">>, <<"/admin/doc/guide.html#", Ref/binary>>},
|
|
||||||
{<<"target">>, <<"_blank">>}],
|
|
||||||
[?C(<<"[Guide: ", Title/binary, "]">>)])])).
|
|
||||||
|
|
||||||
%% h1 with a Guide Link
|
|
||||||
-define(H1GL(Name, Ref, Title),
|
|
||||||
[?XC(<<"h1">>, Name), ?GL(Ref, Title)]).
|
|
|
@ -1,501 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-include("ns.hrl").
|
|
||||||
-include("xml.hrl").
|
|
||||||
|
|
||||||
-define(STANZA_ERROR(Code, Type, Condition),
|
|
||||||
#xmlel{name = <<"error">>,
|
|
||||||
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
|
|
||||||
children =
|
|
||||||
[#xmlel{name = Condition,
|
|
||||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
|
|
||||||
children = []}]}).
|
|
||||||
|
|
||||||
-define(ERR_BAD_FORMAT,
|
|
||||||
?STANZA_ERROR(<<"406">>, <<"modify">>,
|
|
||||||
<<"bad-format">>)).
|
|
||||||
|
|
||||||
-define(ERR_BAD_REQUEST,
|
|
||||||
?STANZA_ERROR(<<"400">>, <<"modify">>,
|
|
||||||
<<"bad-request">>)).
|
|
||||||
|
|
||||||
-define(ERR_CONFLICT,
|
|
||||||
?STANZA_ERROR(<<"409">>, <<"cancel">>, <<"conflict">>)).
|
|
||||||
|
|
||||||
-define(ERR_FEATURE_NOT_IMPLEMENTED,
|
|
||||||
?STANZA_ERROR(<<"501">>, <<"cancel">>,
|
|
||||||
<<"feature-not-implemented">>)).
|
|
||||||
|
|
||||||
-define(ERR_FORBIDDEN,
|
|
||||||
?STANZA_ERROR(<<"403">>, <<"auth">>, <<"forbidden">>)).
|
|
||||||
|
|
||||||
-define(ERR_GONE,
|
|
||||||
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"gone">>)).
|
|
||||||
|
|
||||||
-define(ERR_INTERNAL_SERVER_ERROR,
|
|
||||||
?STANZA_ERROR(<<"500">>, <<"wait">>,
|
|
||||||
<<"internal-server-error">>)).
|
|
||||||
|
|
||||||
-define(ERR_ITEM_NOT_FOUND,
|
|
||||||
?STANZA_ERROR(<<"404">>, <<"cancel">>,
|
|
||||||
<<"item-not-found">>)).
|
|
||||||
|
|
||||||
-define(ERR_JID_MALFORMED,
|
|
||||||
?STANZA_ERROR(<<"400">>, <<"modify">>,
|
|
||||||
<<"jid-malformed">>)).
|
|
||||||
|
|
||||||
-define(ERR_NOT_ACCEPTABLE,
|
|
||||||
?STANZA_ERROR(<<"406">>, <<"modify">>,
|
|
||||||
<<"not-acceptable">>)).
|
|
||||||
|
|
||||||
-define(ERR_NOT_ALLOWED,
|
|
||||||
?STANZA_ERROR(<<"405">>, <<"cancel">>,
|
|
||||||
<<"not-allowed">>)).
|
|
||||||
|
|
||||||
-define(ERR_NOT_AUTHORIZED,
|
|
||||||
?STANZA_ERROR(<<"401">>, <<"auth">>,
|
|
||||||
<<"not-authorized">>)).
|
|
||||||
|
|
||||||
-define(ERR_PAYMENT_REQUIRED,
|
|
||||||
?STANZA_ERROR(<<"402">>, <<"auth">>,
|
|
||||||
<<"payment-required">>)).
|
|
||||||
|
|
||||||
-define(ERR_RECIPIENT_UNAVAILABLE,
|
|
||||||
?STANZA_ERROR(<<"404">>, <<"wait">>,
|
|
||||||
<<"recipient-unavailable">>)).
|
|
||||||
|
|
||||||
-define(ERR_REDIRECT,
|
|
||||||
?STANZA_ERROR(<<"302">>, <<"modify">>, <<"redirect">>)).
|
|
||||||
|
|
||||||
-define(ERR_REGISTRATION_REQUIRED,
|
|
||||||
?STANZA_ERROR(<<"407">>, <<"auth">>,
|
|
||||||
<<"registration-required">>)).
|
|
||||||
|
|
||||||
-define(ERR_REMOTE_SERVER_NOT_FOUND,
|
|
||||||
?STANZA_ERROR(<<"404">>, <<"cancel">>,
|
|
||||||
<<"remote-server-not-found">>)).
|
|
||||||
|
|
||||||
-define(ERR_REMOTE_SERVER_TIMEOUT,
|
|
||||||
?STANZA_ERROR(<<"504">>, <<"wait">>,
|
|
||||||
<<"remote-server-timeout">>)).
|
|
||||||
|
|
||||||
-define(ERR_RESOURCE_CONSTRAINT,
|
|
||||||
?STANZA_ERROR(<<"500">>, <<"wait">>,
|
|
||||||
<<"resource-constraint">>)).
|
|
||||||
|
|
||||||
-define(ERR_SERVICE_UNAVAILABLE,
|
|
||||||
?STANZA_ERROR(<<"503">>, <<"cancel">>,
|
|
||||||
<<"service-unavailable">>)).
|
|
||||||
|
|
||||||
-define(ERR_SUBSCRIPTION_REQUIRED,
|
|
||||||
?STANZA_ERROR(<<"407">>, <<"auth">>,
|
|
||||||
<<"subscription-required">>)).
|
|
||||||
|
|
||||||
-define(ERR_UNEXPECTED_REQUEST,
|
|
||||||
?STANZA_ERROR(<<"400">>, <<"wait">>,
|
|
||||||
<<"unexpected-request">>)).
|
|
||||||
|
|
||||||
-define(ERR_UNEXPECTED_REQUEST_CANCEL,
|
|
||||||
?STANZA_ERROR(<<"401">>, <<"cancel">>,
|
|
||||||
<<"unexpected-request">>)).
|
|
||||||
|
|
||||||
%-define(ERR_,
|
|
||||||
% ?STANZA_ERROR("", "", "")).
|
|
||||||
|
|
||||||
-define(STANZA_ERRORT(Code, Type, Condition, Lang,
|
|
||||||
Text),
|
|
||||||
#xmlel{name = <<"error">>,
|
|
||||||
attrs = [{<<"code">>, Code}, {<<"type">>, Type}],
|
|
||||||
children =
|
|
||||||
[#xmlel{name = Condition,
|
|
||||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}], children = []},
|
|
||||||
#xmlel{name = <<"text">>,
|
|
||||||
attrs = [{<<"xmlns">>, ?NS_STANZAS}],
|
|
||||||
children =
|
|
||||||
[{xmlcdata,
|
|
||||||
translate:translate(Lang, Text)}]}]}).
|
|
||||||
|
|
||||||
-define(ERRT_BAD_FORMAT(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"406">>, <<"modify">>,
|
|
||||||
<<"bad-format">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_BAD_REQUEST(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"400">>, <<"modify">>,
|
|
||||||
<<"bad-request">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_CONFLICT(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"409">>, <<"cancel">>, <<"conflict">>,
|
|
||||||
Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_FEATURE_NOT_IMPLEMENTED(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"501">>, <<"cancel">>,
|
|
||||||
<<"feature-not-implemented">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_FORBIDDEN(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"403">>, <<"auth">>, <<"forbidden">>,
|
|
||||||
Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_GONE(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"gone">>,
|
|
||||||
Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"500">>, <<"wait">>,
|
|
||||||
<<"internal-server-error">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_ITEM_NOT_FOUND(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
|
|
||||||
<<"item-not-found">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_JID_MALFORMED(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"400">>, <<"modify">>,
|
|
||||||
<<"jid-malformed">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_NOT_ACCEPTABLE(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"406">>, <<"modify">>,
|
|
||||||
<<"not-acceptable">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_NOT_ALLOWED(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"405">>, <<"cancel">>,
|
|
||||||
<<"not-allowed">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_NOT_AUTHORIZED(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"401">>, <<"auth">>,
|
|
||||||
<<"not-authorized">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_PAYMENT_REQUIRED(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"402">>, <<"auth">>,
|
|
||||||
<<"payment-required">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_RECIPIENT_UNAVAILABLE(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"404">>, <<"wait">>,
|
|
||||||
<<"recipient-unavailable">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_REDIRECT(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"302">>, <<"modify">>, <<"redirect">>,
|
|
||||||
Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_REGISTRATION_REQUIRED(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"407">>, <<"auth">>,
|
|
||||||
<<"registration-required">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_REMOTE_SERVER_NOT_FOUND(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"404">>, <<"cancel">>,
|
|
||||||
<<"remote-server-not-found">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_REMOTE_SERVER_TIMEOUT(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"504">>, <<"wait">>,
|
|
||||||
<<"remote-server-timeout">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_RESOURCE_CONSTRAINT(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"500">>, <<"wait">>,
|
|
||||||
<<"resource-constraint">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_SERVICE_UNAVAILABLE(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"503">>, <<"cancel">>,
|
|
||||||
<<"service-unavailable">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_SUBSCRIPTION_REQUIRED(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"407">>, <<"auth">>,
|
|
||||||
<<"subscription-required">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERRT_UNEXPECTED_REQUEST(Lang, Text),
|
|
||||||
?STANZA_ERRORT(<<"400">>, <<"wait">>,
|
|
||||||
<<"unexpected-request">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(ERR_AUTH_NO_RESOURCE_PROVIDED(Lang),
|
|
||||||
?ERRT_NOT_ACCEPTABLE(Lang, <<"No resource provided">>)).
|
|
||||||
|
|
||||||
-define(ERR_AUTH_BAD_RESOURCE_FORMAT(Lang),
|
|
||||||
?ERRT_NOT_ACCEPTABLE(Lang,
|
|
||||||
<<"Illegal resource format">>)).
|
|
||||||
|
|
||||||
-define(ERR_AUTH_RESOURCE_CONFLICT(Lang),
|
|
||||||
?ERRT_CONFLICT(Lang, <<"Resource conflict">>)).
|
|
||||||
|
|
||||||
-define(STREAM_ERROR(Condition, Cdata),
|
|
||||||
#xmlel{name = <<"stream:error">>, attrs = [],
|
|
||||||
children =
|
|
||||||
[#xmlel{name = Condition,
|
|
||||||
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
|
|
||||||
children = [{xmlcdata, Cdata}]}]}).
|
|
||||||
|
|
||||||
-define(SERR_BAD_FORMAT,
|
|
||||||
?STREAM_ERROR(<<"bad-format">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_BAD_NAMESPACE_PREFIX,
|
|
||||||
?STREAM_ERROR(<<"bad-namespace-prefix">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_CONFLICT,
|
|
||||||
?STREAM_ERROR(<<"conflict">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_CONNECTION_TIMEOUT,
|
|
||||||
?STREAM_ERROR(<<"connection-timeout">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_HOST_GONE,
|
|
||||||
?STREAM_ERROR(<<"host-gone">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_HOST_UNKNOWN,
|
|
||||||
?STREAM_ERROR(<<"host-unknown">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_IMPROPER_ADDRESSING,
|
|
||||||
?STREAM_ERROR(<<"improper-addressing">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_INTERNAL_SERVER_ERROR,
|
|
||||||
?STREAM_ERROR(<<"internal-server-error">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_INVALID_FROM,
|
|
||||||
?STREAM_ERROR(<<"invalid-from">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_INVALID_ID,
|
|
||||||
?STREAM_ERROR(<<"invalid-id">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_INVALID_NAMESPACE,
|
|
||||||
?STREAM_ERROR(<<"invalid-namespace">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_INVALID_XML,
|
|
||||||
?STREAM_ERROR(<<"invalid-xml">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_NOT_AUTHORIZED,
|
|
||||||
?STREAM_ERROR(<<"not-authorized">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_POLICY_VIOLATION,
|
|
||||||
?STREAM_ERROR(<<"policy-violation">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_REMOTE_CONNECTION_FAILED,
|
|
||||||
?STREAM_ERROR(<<"remote-connection-failed">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_RESOURSE_CONSTRAINT,
|
|
||||||
?STREAM_ERROR(<<"resource-constraint">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_RESTRICTED_XML,
|
|
||||||
?STREAM_ERROR(<<"restricted-xml">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_SEE_OTHER_HOST(Host),
|
|
||||||
?STREAM_ERROR(<<"see-other-host">>, Host)).
|
|
||||||
|
|
||||||
-define(SERR_SYSTEM_SHUTDOWN,
|
|
||||||
?STREAM_ERROR(<<"system-shutdown">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_UNSUPPORTED_ENCODING,
|
|
||||||
?STREAM_ERROR(<<"unsupported-encoding">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_UNSUPPORTED_STANZA_TYPE,
|
|
||||||
?STREAM_ERROR(<<"unsupported-stanza-type">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_UNSUPPORTED_VERSION,
|
|
||||||
?STREAM_ERROR(<<"unsupported-version">>, <<"">>)).
|
|
||||||
|
|
||||||
-define(SERR_XML_NOT_WELL_FORMED,
|
|
||||||
?STREAM_ERROR(<<"xml-not-well-formed">>, <<"">>)).
|
|
||||||
|
|
||||||
%-define(SERR_,
|
|
||||||
% ?STREAM_ERROR("", "")).
|
|
||||||
|
|
||||||
-define(STREAM_ERRORT(Condition, Cdata, Lang, Text),
|
|
||||||
#xmlel{name = <<"stream:error">>, attrs = [],
|
|
||||||
children =
|
|
||||||
[#xmlel{name = Condition,
|
|
||||||
attrs = [{<<"xmlns">>, ?NS_STREAMS}],
|
|
||||||
children = [{xmlcdata, Cdata}]},
|
|
||||||
#xmlel{name = <<"text">>,
|
|
||||||
attrs =
|
|
||||||
[{<<"xml:lang">>, Lang},
|
|
||||||
{<<"xmlns">>, ?NS_STREAMS}],
|
|
||||||
children =
|
|
||||||
[{xmlcdata,
|
|
||||||
translate:translate(Lang, Text)}]}]}).
|
|
||||||
|
|
||||||
-define(SERRT_BAD_FORMAT(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"bad-format">>, <<"">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"bad-namespace-prefix">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_CONFLICT(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"conflict">>, <<"">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"connection-timeout">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_HOST_GONE(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"host-gone">>, <<"">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_HOST_UNKNOWN(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"host-unknown">>, <<"">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"improper-addressing">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"internal-server-error">>, <<"">>,
|
|
||||||
Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_INVALID_FROM(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"invalid-from">>, <<"">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_INVALID_ID(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"invalid-id">>, <<"">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_INVALID_NAMESPACE(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"invalid-namespace">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_INVALID_XML(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"invalid-xml">>, <<"">>, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_NOT_AUTHORIZED(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"not-authorized">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_POLICY_VIOLATION(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"policy-violation">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"remote-connection-failed">>, <<"">>,
|
|
||||||
Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"resource-constraint">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_RESTRICTED_XML(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"restricted-xml">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_SEE_OTHER_HOST(Host, Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"see-other-host">>, Host, Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"system-shutdown">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"unsupported-encoding">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"unsupported-stanza-type">>, <<"">>,
|
|
||||||
Lang, Text)).
|
|
||||||
|
|
||||||
-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"unsupported-version">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
|
|
||||||
?STREAM_ERRORT(<<"xml-not-well-formed">>, <<"">>, Lang,
|
|
||||||
Text)).
|
|
||||||
|
|
||||||
-record(jid, {user = <<"">> :: binary(),
|
|
||||||
server = <<"">> :: binary(),
|
|
||||||
resource = <<"">> :: binary(),
|
|
||||||
luser = <<"">> :: binary(),
|
|
||||||
lserver = <<"">> :: binary(),
|
|
||||||
lresource = <<"">> :: binary()}).
|
|
||||||
|
|
||||||
-type(jid() :: #jid{}).
|
|
||||||
|
|
||||||
-type(ljid() :: {binary(), binary(), binary()}).
|
|
||||||
|
|
||||||
-record(iq, {id = <<"">> :: binary(),
|
|
||||||
type = get :: get | set | result | error,
|
|
||||||
xmlns = <<"">> :: binary(),
|
|
||||||
lang = <<"">> :: binary(),
|
|
||||||
sub_el = #xmlel{} :: xmlel() | [xmlel()]}).
|
|
||||||
|
|
||||||
-type(iq_get()
|
|
||||||
:: #iq{
|
|
||||||
id :: binary(),
|
|
||||||
type :: get,
|
|
||||||
xmlns :: binary(),
|
|
||||||
lang :: binary(),
|
|
||||||
sub_el :: xmlel()
|
|
||||||
}
|
|
||||||
).
|
|
||||||
|
|
||||||
-type(iq_set()
|
|
||||||
:: #iq{
|
|
||||||
id :: binary(),
|
|
||||||
type :: set,
|
|
||||||
xmlns :: binary(),
|
|
||||||
lang :: binary(),
|
|
||||||
sub_el :: xmlel()
|
|
||||||
}
|
|
||||||
).
|
|
||||||
|
|
||||||
-type iq_request() :: iq_get() | iq_set().
|
|
||||||
|
|
||||||
-type(iq_result()
|
|
||||||
:: #iq{
|
|
||||||
id :: binary(),
|
|
||||||
type :: result,
|
|
||||||
xmlns :: binary(),
|
|
||||||
lang :: binary(),
|
|
||||||
sub_el :: [xmlel()]
|
|
||||||
}
|
|
||||||
).
|
|
||||||
|
|
||||||
-type(iq_error()
|
|
||||||
:: #iq{
|
|
||||||
id :: binary(),
|
|
||||||
type :: error,
|
|
||||||
xmlns :: binary(),
|
|
||||||
lang :: binary(),
|
|
||||||
sub_el :: [xmlel()]
|
|
||||||
}
|
|
||||||
).
|
|
||||||
|
|
||||||
-type iq_reply() :: iq_result() | iq_error() .
|
|
||||||
|
|
||||||
-type(iq() :: iq_request() | iq_reply()).
|
|
||||||
|
|
||||||
-record(rsm_in, {max :: integer(),
|
|
||||||
direction :: before | aft,
|
|
||||||
id :: binary(),
|
|
||||||
index :: integer()}).
|
|
||||||
|
|
||||||
-record(rsm_out, {count :: integer(),
|
|
||||||
index :: integer(),
|
|
||||||
first :: binary(),
|
|
||||||
last :: binary()}).
|
|
||||||
|
|
||||||
-type(rsm_in() :: #rsm_in{}).
|
|
||||||
|
|
||||||
-type(rsm_out() :: #rsm_out{}).
|
|
||||||
|
|
||||||
-type broadcast() :: {broadcast, broadcast_data()}.
|
|
||||||
|
|
||||||
-type broadcast_data() ::
|
|
||||||
{rebind, pid(), binary()} | %% ejabberd_c2s
|
|
||||||
{item, ljid(), mod_roster:subscription()} | %% mod_roster/mod_shared_roster
|
|
||||||
{exit, binary()} | %% mod_roster/mod_shared_roster
|
|
||||||
{privacy_list, mod_privacy:userlist(), binary()} | %% mod_privacy
|
|
||||||
{blocking, unblock_all | {block | unblock, [ljid()]}}. %% mod_blocking
|
|
||||||
|
|
||||||
-record(xmlelement, {name = "" :: string(),
|
|
||||||
attrs = [] :: [{string(), string()}],
|
|
||||||
children = [] :: [{xmlcdata, iodata()} | xmlelement()]}).
|
|
||||||
|
|
||||||
-type xmlelement() :: #xmlelement{}.
|
|
|
@ -1,102 +0,0 @@
|
||||||
%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
|
|
||||||
%%
|
|
||||||
%% This file is provided to you under the Apache License,
|
|
||||||
%% Version 2.0 (the "License"); you may not use this file
|
|
||||||
%% except in compliance with the License. You may obtain
|
|
||||||
%% a copy of the License at
|
|
||||||
%%
|
|
||||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
%%
|
|
||||||
%% Unless required by applicable law or agreed to in writing,
|
|
||||||
%% software distributed under the License is distributed on an
|
|
||||||
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
%% KIND, either express or implied. See the License for the
|
|
||||||
%% specific language governing permissions and limitations
|
|
||||||
%% under the License.
|
|
||||||
|
|
||||||
|
|
||||||
-define(DEFAULT_TRUNCATION, 4096).
|
|
||||||
-define(DEFAULT_TRACER, lager_default_tracer).
|
|
||||||
|
|
||||||
-define(LEVELS,
|
|
||||||
[debug, info, notice, warning, error, critical, alert, emergency, none]).
|
|
||||||
|
|
||||||
-define(DEBUG, 128).
|
|
||||||
-define(INFO, 64).
|
|
||||||
-define(NOTICE, 32).
|
|
||||||
-define(WARNING, 16).
|
|
||||||
-define(ERROR, 8).
|
|
||||||
-define(CRITICAL, 4).
|
|
||||||
-define(ALERT, 2).
|
|
||||||
-define(EMERGENCY, 1).
|
|
||||||
-define(LOG_NONE, 0).
|
|
||||||
|
|
||||||
-define(LEVEL2NUM(Level),
|
|
||||||
case Level of
|
|
||||||
debug -> ?DEBUG;
|
|
||||||
info -> ?INFO;
|
|
||||||
notice -> ?NOTICE;
|
|
||||||
warning -> ?WARNING;
|
|
||||||
error -> ?ERROR;
|
|
||||||
critical -> ?CRITICAL;
|
|
||||||
alert -> ?ALERT;
|
|
||||||
emergency -> ?EMERGENCY
|
|
||||||
end).
|
|
||||||
|
|
||||||
-define(NUM2LEVEL(Num),
|
|
||||||
case Num of
|
|
||||||
?DEBUG -> debug;
|
|
||||||
?INFO -> info;
|
|
||||||
?NOTICE -> notice;
|
|
||||||
?WARNING -> warning;
|
|
||||||
?ERROR -> error;
|
|
||||||
?CRITICAL -> critical;
|
|
||||||
?ALERT -> alert;
|
|
||||||
?EMERGENCY -> emergency
|
|
||||||
end).
|
|
||||||
|
|
||||||
-define(SHOULD_LOG(Level),
|
|
||||||
(lager_util:level_to_num(Level) band element(1, lager_config:get(loglevel, {?LOG_NONE, []}))) /= 0).
|
|
||||||
|
|
||||||
-define(NOTIFY(Level, Pid, Format, Args),
|
|
||||||
gen_event:notify(lager_event, {log, lager_msg:new(io_lib:format(Format, Args),
|
|
||||||
Level,
|
|
||||||
[{pid,Pid},{line,?LINE},{file,?FILE},{module,?MODULE}],
|
|
||||||
[])}
|
|
||||||
)).
|
|
||||||
|
|
||||||
%% FOR INTERNAL USE ONLY
|
|
||||||
%% internal non-blocking logging call
|
|
||||||
%% there's some special handing for when we try to log (usually errors) while
|
|
||||||
%% lager is still starting.
|
|
||||||
-ifdef(TEST).
|
|
||||||
-define(INT_LOG(Level, Format, Args),
|
|
||||||
case ?SHOULD_LOG(Level) of
|
|
||||||
true ->
|
|
||||||
?NOTIFY(Level, self(), Format, Args);
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end).
|
|
||||||
-else.
|
|
||||||
-define(INT_LOG(Level, Format, Args),
|
|
||||||
Self = self(),
|
|
||||||
%% do this in a spawn so we don't cause a deadlock calling gen_event:which_handlers
|
|
||||||
%% from a gen_event handler
|
|
||||||
spawn(fun() ->
|
|
||||||
case catch(gen_event:which_handlers(lager_event)) of
|
|
||||||
X when X == []; X == {'EXIT', noproc}; X == [lager_backend_throttle] ->
|
|
||||||
%% there's no handlers yet or lager isn't running, try again
|
|
||||||
%% in half a second.
|
|
||||||
timer:sleep(500),
|
|
||||||
?NOTIFY(Level, Self, Format, Args);
|
|
||||||
_ ->
|
|
||||||
case ?SHOULD_LOG(Level) of
|
|
||||||
true ->
|
|
||||||
?NOTIFY(Level, Self, Format, Args);
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)).
|
|
||||||
-endif.
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
-define(PRINT(Format, Args), io:format(Format, Args)).
|
|
||||||
|
|
||||||
-ifdef(LAGER).
|
|
||||||
-compile([{parse_transform, lager_transform}]).
|
|
||||||
|
|
||||||
-define(DEBUG(Format, Args),
|
|
||||||
lager:debug(Format, Args)).
|
|
||||||
|
|
||||||
-define(INFO_MSG(Format, Args),
|
|
||||||
lager:info(Format, Args)).
|
|
||||||
|
|
||||||
-define(WARNING_MSG(Format, Args),
|
|
||||||
lager:warning(Format, Args)).
|
|
||||||
|
|
||||||
-define(ERROR_MSG(Format, Args),
|
|
||||||
lager:error(Format, Args)).
|
|
||||||
|
|
||||||
-define(CRITICAL_MSG(Format, Args),
|
|
||||||
lager:critical(Format, Args)).
|
|
||||||
|
|
||||||
-else.
|
|
||||||
|
|
||||||
-define(DEBUG(Format, Args),
|
|
||||||
p1_logger:debug_msg(?MODULE, ?LINE, Format, Args)).
|
|
||||||
|
|
||||||
-define(INFO_MSG(Format, Args),
|
|
||||||
p1_logger:info_msg(?MODULE, ?LINE, Format, Args)).
|
|
||||||
|
|
||||||
-define(WARNING_MSG(Format, Args),
|
|
||||||
p1_logger:warning_msg(?MODULE, ?LINE, Format, Args)).
|
|
||||||
|
|
||||||
-define(ERROR_MSG(Format, Args),
|
|
||||||
p1_logger:error_msg(?MODULE, ?LINE, Format, Args)).
|
|
||||||
|
|
||||||
-define(CRITICAL_MSG(Format, Args),
|
|
||||||
p1_logger:critical_msg(?MODULE, ?LINE, Format, Args)).
|
|
||||||
-endif.
|
|
|
@ -1,116 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-define(MAX_USERS_DEFAULT, 200).
|
|
||||||
|
|
||||||
-define(SETS, gb_sets).
|
|
||||||
|
|
||||||
-define(DICT, dict).
|
|
||||||
|
|
||||||
-record(lqueue,
|
|
||||||
{
|
|
||||||
queue :: queue(),
|
|
||||||
len :: integer(),
|
|
||||||
max :: integer()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-type lqueue() :: #lqueue{}.
|
|
||||||
|
|
||||||
-record(config,
|
|
||||||
{
|
|
||||||
title = <<"">> :: binary(),
|
|
||||||
description = <<"">> :: binary(),
|
|
||||||
allow_change_subj = true :: boolean(),
|
|
||||||
allow_query_users = true :: boolean(),
|
|
||||||
allow_private_messages = true :: boolean(),
|
|
||||||
allow_private_messages_from_visitors = anyone :: anyone | moderators | nobody ,
|
|
||||||
allow_visitor_status = true :: boolean(),
|
|
||||||
allow_visitor_nickchange = true :: boolean(),
|
|
||||||
public = true :: boolean(),
|
|
||||||
public_list = true :: boolean(),
|
|
||||||
persistent = false :: boolean(),
|
|
||||||
moderated = true :: boolean(),
|
|
||||||
captcha_protected = false :: boolean(),
|
|
||||||
members_by_default = true :: boolean(),
|
|
||||||
members_only = false :: boolean(),
|
|
||||||
allow_user_invites = false :: boolean(),
|
|
||||||
password_protected = false :: boolean(),
|
|
||||||
password = <<"">> :: binary(),
|
|
||||||
anonymous = true :: boolean(),
|
|
||||||
allow_voice_requests = true :: boolean(),
|
|
||||||
voice_request_min_interval = 1800 :: non_neg_integer(),
|
|
||||||
max_users = ?MAX_USERS_DEFAULT :: non_neg_integer() | none,
|
|
||||||
logging = false :: boolean(),
|
|
||||||
vcard = <<"">> :: boolean(),
|
|
||||||
captcha_whitelist = (?SETS):empty() :: gb_set()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-type config() :: #config{}.
|
|
||||||
|
|
||||||
-type role() :: moderator | participant | visitor | none.
|
|
||||||
|
|
||||||
-record(user,
|
|
||||||
{
|
|
||||||
jid :: jid(),
|
|
||||||
nick :: binary(),
|
|
||||||
role :: role(),
|
|
||||||
last_presence :: xmlel()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-record(activity,
|
|
||||||
{
|
|
||||||
message_time = 0 :: integer(),
|
|
||||||
presence_time = 0 :: integer(),
|
|
||||||
message_shaper :: shaper:shaper(),
|
|
||||||
presence_shaper :: shaper:shaper(),
|
|
||||||
message :: xmlel(),
|
|
||||||
presence :: {binary(), xmlel()}
|
|
||||||
}).
|
|
||||||
|
|
||||||
-record(state,
|
|
||||||
{
|
|
||||||
room = <<"">> :: binary(),
|
|
||||||
host = <<"">> :: binary(),
|
|
||||||
server_host = <<"">> :: binary(),
|
|
||||||
access = {none,none,none,none} :: {atom(), atom(), atom(), atom()},
|
|
||||||
jid = #jid{} :: jid(),
|
|
||||||
config = #config{} :: config(),
|
|
||||||
users = (?DICT):new() :: dict(),
|
|
||||||
last_voice_request_time = treap:empty() :: treap:treap(),
|
|
||||||
robots = (?DICT):new() :: dict(),
|
|
||||||
nicks = (?DICT):new() :: dict(),
|
|
||||||
affiliations = (?DICT):new() :: dict(),
|
|
||||||
history :: lqueue(),
|
|
||||||
subject = <<"">> :: binary(),
|
|
||||||
subject_author = <<"">> :: binary(),
|
|
||||||
just_created = false :: boolean(),
|
|
||||||
activity = treap:empty() :: treap:treap(),
|
|
||||||
room_shaper = none :: shaper:shaper(),
|
|
||||||
room_queue = queue:new() :: queue()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-record(muc_online_users, {us = {<<>>, <<>>} :: {binary(), binary()},
|
|
||||||
resource = <<>> :: binary() | '_',
|
|
||||||
room = <<>> :: binary() | '_',
|
|
||||||
host = <<>> :: binary() | '_'}).
|
|
||||||
|
|
||||||
-type muc_online_users() :: #muc_online_users{}.
|
|
||||||
|
|
||||||
-type muc_room_state() :: #state{}.
|
|
|
@ -1,41 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-record(roster,
|
|
||||||
{
|
|
||||||
usj = {<<>>, <<>>, {<<>>, <<>>, <<>>}} :: {binary(), binary(), ljid()} | '_',
|
|
||||||
us = {<<>>, <<>>} :: {binary(), binary()} | '_',
|
|
||||||
jid = {<<>>, <<>>, <<>>} :: ljid(),
|
|
||||||
name = <<>> :: binary() | '_',
|
|
||||||
subscription = none :: subscription() | '_',
|
|
||||||
ask = none :: ask() | '_',
|
|
||||||
groups = [] :: [binary()] | '_',
|
|
||||||
askmessage = <<"">> :: binary() | '_',
|
|
||||||
xs = [] :: [xmlel()] | '_'
|
|
||||||
}).
|
|
||||||
|
|
||||||
-record(roster_version,
|
|
||||||
{
|
|
||||||
us = {<<>>, <<>>} :: {binary(), binary()},
|
|
||||||
version = <<>> :: binary()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-type ask() :: none | in | out | both | subscribe | unsubscribe.
|
|
||||||
-type subscription() :: none | both | from | to | remove.
|
|
|
@ -1,152 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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.
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-define(NS_DISCO_ITEMS,
|
|
||||||
<<"http://jabber.org/protocol/disco#items">>).
|
|
||||||
-define(NS_DISCO_INFO,
|
|
||||||
<<"http://jabber.org/protocol/disco#info">>).
|
|
||||||
-define(NS_VCARD, <<"vcard-temp">>).
|
|
||||||
-define(NS_VCARD_UPDATE, <<"vcard-temp:x:update">>).
|
|
||||||
-define(NS_AUTH, <<"jabber:iq:auth">>).
|
|
||||||
-define(NS_AUTH_ERROR, <<"jabber:iq:auth:error">>).
|
|
||||||
-define(NS_REGISTER, <<"jabber:iq:register">>).
|
|
||||||
-define(NS_SEARCH, <<"jabber:iq:search">>).
|
|
||||||
-define(NS_ROSTER, <<"jabber:iq:roster">>).
|
|
||||||
-define(NS_ROSTER_VER,
|
|
||||||
<<"urn:xmpp:features:rosterver">>).
|
|
||||||
-define(NS_PRIVACY, <<"jabber:iq:privacy">>).
|
|
||||||
-define(NS_BLOCKING, <<"urn:xmpp:blocking">>).
|
|
||||||
-define(NS_PRIVATE, <<"jabber:iq:private">>).
|
|
||||||
-define(NS_VERSION, <<"jabber:iq:version">>).
|
|
||||||
-define(NS_TIME90, <<"jabber:iq:time">>).
|
|
||||||
-define(NS_TIME, <<"urn:xmpp:time">>).
|
|
||||||
-define(NS_LAST, <<"jabber:iq:last">>).
|
|
||||||
-define(NS_XDATA, <<"jabber:x:data">>).
|
|
||||||
-define(NS_IQDATA, <<"jabber:iq:data">>).
|
|
||||||
-define(NS_DELAY91, <<"jabber:x:delay">>).
|
|
||||||
-define(NS_DELAY, <<"urn:xmpp:delay">>).
|
|
||||||
-define(NS_HINTS, <<"urn:xmpp:hints">>).
|
|
||||||
-define(NS_EXPIRE, <<"jabber:x:expire">>).
|
|
||||||
-define(NS_EVENT, <<"jabber:x:event">>).
|
|
||||||
-define(NS_CHATSTATES,
|
|
||||||
<<"http://jabber.org/protocol/chatstates">>).
|
|
||||||
-define(NS_XCONFERENCE, <<"jabber:x:conference">>).
|
|
||||||
-define(NS_STATS,
|
|
||||||
<<"http://jabber.org/protocol/stats">>).
|
|
||||||
-define(NS_MUC, <<"http://jabber.org/protocol/muc">>).
|
|
||||||
-define(NS_MUC_USER,
|
|
||||||
<<"http://jabber.org/protocol/muc#user">>).
|
|
||||||
-define(NS_MUC_ADMIN,
|
|
||||||
<<"http://jabber.org/protocol/muc#admin">>).
|
|
||||||
-define(NS_MUC_OWNER,
|
|
||||||
<<"http://jabber.org/protocol/muc#owner">>).
|
|
||||||
-define(NS_MUC_UNIQUE,
|
|
||||||
<<"http://jabber.org/protocol/muc#unique">>).
|
|
||||||
-define(NS_PUBSUB,
|
|
||||||
<<"http://jabber.org/protocol/pubsub">>).
|
|
||||||
-define(NS_PUBSUB_EVENT,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#event">>).
|
|
||||||
-define(NS_PUBSUB_META_DATA,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#meta-data">>).
|
|
||||||
-define(NS_PUBSUB_OWNER,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#owner">>).
|
|
||||||
-define(NS_PUBSUB_NMI,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#node-meta-info">>).
|
|
||||||
-define(NS_PUBSUB_ERRORS,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#errors">>).
|
|
||||||
-define(NS_PUBSUB_NODE_CONFIG,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#node_config">>).
|
|
||||||
-define(NS_PUBSUB_SUB_OPTIONS,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
|
|
||||||
-define(NS_PUBSUB_SUBSCRIBE_OPTIONS,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#subscribe_options">>).
|
|
||||||
-define(NS_PUBSUB_PUBLISH_OPTIONS,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#publish_options">>).
|
|
||||||
-define(NS_PUBSUB_SUB_AUTH,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#subscribe_authorization">>).
|
|
||||||
-define(NS_PUBSUB_GET_PENDING,
|
|
||||||
<<"http://jabber.org/protocol/pubsub#get-pending">>).
|
|
||||||
-define(NS_COMMANDS,
|
|
||||||
<<"http://jabber.org/protocol/commands">>).
|
|
||||||
-define(NS_BYTESTREAMS,
|
|
||||||
<<"http://jabber.org/protocol/bytestreams">>).
|
|
||||||
-define(NS_ADMIN,
|
|
||||||
<<"http://jabber.org/protocol/admin">>).
|
|
||||||
-define(NS_ADMIN_ANNOUNCE,
|
|
||||||
<<"http://jabber.org/protocol/admin#announce">>).
|
|
||||||
-define(NS_ADMIN_ANNOUNCE_ALL,
|
|
||||||
<<"http://jabber.org/protocol/admin#announce-all">>).
|
|
||||||
-define(NS_ADMIN_SET_MOTD,
|
|
||||||
<<"http://jabber.org/protocol/admin#set-motd">>).
|
|
||||||
-define(NS_ADMIN_EDIT_MOTD,
|
|
||||||
<<"http://jabber.org/protocol/admin#edit-motd">>).
|
|
||||||
-define(NS_ADMIN_DELETE_MOTD,
|
|
||||||
<<"http://jabber.org/protocol/admin#delete-motd">>).
|
|
||||||
-define(NS_ADMIN_ANNOUNCE_ALLHOSTS,
|
|
||||||
<<"http://jabber.org/protocol/admin#announce-allhosts">>).
|
|
||||||
-define(NS_ADMIN_ANNOUNCE_ALL_ALLHOSTS,
|
|
||||||
<<"http://jabber.org/protocol/admin#announce-all-allhosts">>).
|
|
||||||
-define(NS_ADMIN_SET_MOTD_ALLHOSTS,
|
|
||||||
<<"http://jabber.org/protocol/admin#set-motd-allhosts">>).
|
|
||||||
-define(NS_ADMIN_EDIT_MOTD_ALLHOSTS,
|
|
||||||
<<"http://jabber.org/protocol/admin#edit-motd-allhosts">>).
|
|
||||||
-define(NS_ADMIN_DELETE_MOTD_ALLHOSTS,
|
|
||||||
<<"http://jabber.org/protocol/admin#delete-motd-allhosts">>).
|
|
||||||
-define(NS_SERVERINFO,
|
|
||||||
<<"http://jabber.org/network/serverinfo">>).
|
|
||||||
-define(NS_RSM, <<"http://jabber.org/protocol/rsm">>).
|
|
||||||
-define(NS_EJABBERD_CONFIG, <<"ejabberd:config">>).
|
|
||||||
-define(NS_STREAM,
|
|
||||||
<<"http://etherx.jabber.org/streams">>).
|
|
||||||
-define(NS_STANZAS,
|
|
||||||
<<"urn:ietf:params:xml:ns:xmpp-stanzas">>).
|
|
||||||
-define(NS_STREAMS,
|
|
||||||
<<"urn:ietf:params:xml:ns:xmpp-streams">>).
|
|
||||||
-define(NS_TLS, <<"urn:ietf:params:xml:ns:xmpp-tls">>).
|
|
||||||
-define(NS_SASL,
|
|
||||||
<<"urn:ietf:params:xml:ns:xmpp-sasl">>).
|
|
||||||
-define(NS_SESSION,
|
|
||||||
<<"urn:ietf:params:xml:ns:xmpp-session">>).
|
|
||||||
-define(NS_BIND,
|
|
||||||
<<"urn:ietf:params:xml:ns:xmpp-bind">>).
|
|
||||||
-define(NS_FEATURE_IQAUTH,
|
|
||||||
<<"http://jabber.org/features/iq-auth">>).
|
|
||||||
-define(NS_FEATURE_IQREGISTER,
|
|
||||||
<<"http://jabber.org/features/iq-register">>).
|
|
||||||
-define(NS_FEATURE_COMPRESS,
|
|
||||||
<<"http://jabber.org/features/compress">>).
|
|
||||||
-define(NS_FEATURE_MSGOFFLINE, <<"msgoffline">>).
|
|
||||||
-define(NS_COMPRESS,
|
|
||||||
<<"http://jabber.org/protocol/compress">>).
|
|
||||||
-define(NS_CAPS, <<"http://jabber.org/protocol/caps">>).
|
|
||||||
-define(NS_SHIM, <<"http://jabber.org/protocol/shim">>).
|
|
||||||
-define(NS_ADDRESS,
|
|
||||||
<<"http://jabber.org/protocol/address">>).
|
|
||||||
-define(NS_OOB, <<"jabber:x:oob">>).
|
|
||||||
-define(NS_CAPTCHA, <<"urn:xmpp:captcha">>).
|
|
||||||
-define(NS_MEDIA, <<"urn:xmpp:media-element">>).
|
|
||||||
-define(NS_BOB, <<"urn:xmpp:bob">>).
|
|
||||||
-define(NS_PING, <<"urn:xmpp:ping">>).
|
|
||||||
-define(NS_CARBONS_2, <<"urn:xmpp:carbons:2">>).
|
|
||||||
-define(NS_CARBONS_1, <<"urn:xmpp:carbons:1">>).
|
|
||||||
-define(NS_FORWARD, <<"urn:xmpp:forward:0">>).
|
|
||||||
-define(NS_CLIENT_STATE, <<"urn:xmpp:csi:0">>).
|
|
||||||
-define(NS_STREAM_MGMT_2, <<"urn:xmpp:sm:2">>).
|
|
||||||
-define(NS_STREAM_MGMT_3, <<"urn:xmpp:sm:3">>).
|
|
|
@ -1,257 +0,0 @@
|
||||||
%%% ====================================================================
|
|
||||||
%%% ``The contents of this file are subject to the Erlang Public License,
|
|
||||||
%%% Version 1.1, (the "License"); you may not use this file except in
|
|
||||||
%%% compliance with the License. You should have received a copy of the
|
|
||||||
%%% Erlang Public License along with this software. If not, it can be
|
|
||||||
%%% retrieved via the world wide web at http://www.erlang.org/.
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% Software distributed under the License is distributed on an "AS IS"
|
|
||||||
%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
||||||
%%% the License for the specific language governing rights and limitations
|
|
||||||
%%% under the License.
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% The Initial Developer of the Original Code is ProcessOne.
|
|
||||||
%%% Portions created by ProcessOne are Copyright 2006-2015, ProcessOne
|
|
||||||
%%% All Rights Reserved.''
|
|
||||||
%%% This software is copyright 2006-2015, ProcessOne.
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% copyright 2006-2015 ProcessOne
|
|
||||||
%%%
|
|
||||||
%%% This file contains pubsub types definition.
|
|
||||||
%%% ====================================================================
|
|
||||||
|
|
||||||
%% -------------------------------
|
|
||||||
%% Pubsub constants
|
|
||||||
-define(ERR_EXTENDED(E, C),
|
|
||||||
mod_pubsub:extended_error(E, C)).
|
|
||||||
|
|
||||||
%% The actual limit can be configured with mod_pubsub's option max_items_node
|
|
||||||
-define(MAXITEMS, 10).
|
|
||||||
|
|
||||||
%% this is currently a hard limit.
|
|
||||||
%% Would be nice to have it configurable.
|
|
||||||
-define(MAX_PAYLOAD_SIZE, 60000).
|
|
||||||
|
|
||||||
%% -------------------------------
|
|
||||||
%% Pubsub types
|
|
||||||
|
|
||||||
%% @type hostPubsub() = string().
|
|
||||||
-type(hostPubsub() :: binary()).
|
|
||||||
%% <p><tt>hostPubsub</tt> is the name of the PubSub service. For example, it can be
|
|
||||||
%% <tt>"pubsub.localhost"</tt>.</p>
|
|
||||||
|
|
||||||
-type(hostPEP() :: {binary(), binary(), <<>>}).
|
|
||||||
%% @type hostPEP() = {User, Server, Resource}
|
|
||||||
%% User = string()
|
|
||||||
%% Server = string()
|
|
||||||
%% Resource = [].
|
|
||||||
%% <p>For example, it can be :
|
|
||||||
%% ```{"bob", "example.org", []}'''.</p>
|
|
||||||
|
|
||||||
-type(host() :: hostPubsub() | hostPEP()).
|
|
||||||
%% @type host() = hostPubsub() | hostPEP().
|
|
||||||
|
|
||||||
-type(nodeId() :: binary()).
|
|
||||||
%% @type nodeId() = binary().
|
|
||||||
%% <p>A node is defined by a list of its ancestors. The last element is the name
|
|
||||||
%% of the current node. For example:
|
|
||||||
%% of the current node. For example:
|
|
||||||
%% ```<<"/home/localhost/user">>'''</p>
|
|
||||||
|
|
||||||
-type(nodeIdx() :: pos_integer()).
|
|
||||||
%% @type nodeIdx() = integer().
|
|
||||||
|
|
||||||
-type(itemId() :: binary()).
|
|
||||||
%% @type itemId() = string().
|
|
||||||
|
|
||||||
-type(subId() :: binary()).
|
|
||||||
%% @type subId() = string().
|
|
||||||
|
|
||||||
|
|
||||||
%% @type payload() = [#xmlelement{} | #xmlcdata{}].
|
|
||||||
|
|
||||||
%% @type stanzaError() = #xmlelement{}.
|
|
||||||
%% Example:
|
|
||||||
%% Example:
|
|
||||||
%% ```{xmlelement, "error",
|
|
||||||
%% [{"code", Code}, {"type", Type}],
|
|
||||||
%% [{xmlelement, Condition, [{"xmlns", ?NS_STANZAS}], []}]}'''
|
|
||||||
%% @type pubsubIQResponse() = #xmlelement{}.
|
|
||||||
%% Example:
|
|
||||||
%% ```{xmlelement, "pubsub",
|
|
||||||
%% [{"xmlns", ?NS_PUBSUB_EVENT}],
|
|
||||||
%% [{xmlelement, "affiliations", [],
|
|
||||||
%% []}]}'''
|
|
||||||
|
|
||||||
-type(nodeOption() ::
|
|
||||||
{Option::atom(),
|
|
||||||
Value::binary() | [binary()] | boolean() | non_neg_integer()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-type(nodeOptions() :: [NodeOption::mod_pubsub:nodeOption(),...]).
|
|
||||||
|
|
||||||
%% @type nodeOption() = {Option, Value}
|
|
||||||
%% Option = atom()
|
|
||||||
%% Value = term().
|
|
||||||
%% Example:
|
|
||||||
%% ```{deliver_payloads, true}'''
|
|
||||||
|
|
||||||
-type(subOption() ::
|
|
||||||
{Option::atom(),
|
|
||||||
Value::binary() | [binary()] | boolean()
|
|
||||||
}).
|
|
||||||
|
|
||||||
-type(subOptions() :: [SubOption::mod_pubsub:subOption(),...]).
|
|
||||||
|
|
||||||
%% @type nodeType() = string().
|
|
||||||
%% <p>The <tt>nodeType</tt> is a string containing the name of the PubSub
|
|
||||||
%% plugin to use to manage a given node. For example, it can be
|
|
||||||
%% <tt>"flat"</tt>, <tt>"hometree"</tt> or <tt>"blog"</tt>.</p>
|
|
||||||
|
|
||||||
%% @type jid() = {jid, User, Server, Resource, LUser, LServer, LResource}
|
|
||||||
%% User = string()
|
|
||||||
%% Server = string()
|
|
||||||
%% Resource = string()
|
|
||||||
%% LUser = string()
|
|
||||||
%% LServer = string()
|
|
||||||
%% LResource = string().
|
|
||||||
|
|
||||||
%-type(ljid() :: {binary(), binary(), binary()}).
|
|
||||||
%% @type ljid() = {User, Server, Resource}
|
|
||||||
%% User = string()
|
|
||||||
%% Server = string()
|
|
||||||
%% Resource = string().
|
|
||||||
|
|
||||||
-type(affiliation() :: 'none'
|
|
||||||
| 'owner'
|
|
||||||
| 'publisher'
|
|
||||||
%| 'publish-only'
|
|
||||||
| 'member'
|
|
||||||
| 'outcast'
|
|
||||||
).
|
|
||||||
%% @type affiliation() = 'none' | 'owner' | 'publisher' | 'publish-only' | 'member' | 'outcast'.
|
|
||||||
|
|
||||||
-type(subscription() :: 'none'
|
|
||||||
| 'pending'
|
|
||||||
| 'unconfigured'
|
|
||||||
| 'subscribed'
|
|
||||||
).
|
|
||||||
%% @type subscription() = 'none' | 'pending' | 'unconfigured' | 'subscribed'.
|
|
||||||
|
|
||||||
-type(accessModel() :: 'open'
|
|
||||||
| 'presence'
|
|
||||||
| 'roster'
|
|
||||||
| 'authorize'
|
|
||||||
| 'whitelist'
|
|
||||||
).
|
|
||||||
%% @type accessModel() = 'open' | 'presence' | 'roster' | 'authorize' | 'whitelist'.
|
|
||||||
|
|
||||||
%% @type pubsubIndex() = {pubsub_index, Index, Last, Free}
|
|
||||||
%% Index = atom()
|
|
||||||
%% Last = integer()
|
|
||||||
%% Free = [integer()].
|
|
||||||
%% internal pubsub index table
|
|
||||||
-type(publishModel() :: 'publishers'
|
|
||||||
| 'subscribers'
|
|
||||||
| 'open'
|
|
||||||
).
|
|
||||||
|
|
||||||
|
|
||||||
-record(pubsub_index,
|
|
||||||
{
|
|
||||||
index :: atom(),
|
|
||||||
last :: mod_pubsub:nodeIdx(),
|
|
||||||
free :: [mod_pubsub:nodeIdx()]
|
|
||||||
}).
|
|
||||||
|
|
||||||
%% @type pubsubNode() = {pubsub_node, NodeId, Id, Parents, Type, Owners, Options}
|
|
||||||
%% NodeId = {host() | ljid(), nodeId()}
|
|
||||||
%% Id = nodeIdx()
|
|
||||||
%% Parents = [nodeId()]
|
|
||||||
%% Type = nodeType()
|
|
||||||
%% Owners = [ljid()]
|
|
||||||
%% Options = [nodeOption()].
|
|
||||||
%% <p>This is the format of the <tt>nodes</tt> table. The type of the table
|
|
||||||
%% is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
|
||||||
%% <p>The <tt>Parents</tt> and <tt>type</tt> fields are indexed.</p>
|
|
||||||
%% <tt>id</tt> can be anything you want.
|
|
||||||
-record(pubsub_node,
|
|
||||||
{
|
|
||||||
nodeid ,%:: {Host::mod_pubsub:host(), NodeId::mod_pubsub:nodeId()},
|
|
||||||
id ,%:: mod_pubsub:nodeIdx(),
|
|
||||||
parents = [] ,%:: [Parent_NodeId::mod_pubsub:nodeId()],
|
|
||||||
type = <<"flat">> ,%:: binary(),
|
|
||||||
owners = [] ,%:: [Owner::ljid(),...],
|
|
||||||
options = [] %:: mod_pubsub:nodeOptions()
|
|
||||||
}).
|
|
||||||
|
|
||||||
%% @type pubsubState() = {pubsub_state, StateId, Items, Affiliation, Subscriptions}
|
|
||||||
%% StateId = {ljid(), nodeIdx()}
|
|
||||||
%% Items = [itemId()]
|
|
||||||
%% Affiliation = affiliation()
|
|
||||||
%% Subscriptions = [{subscription(), subId()}].
|
|
||||||
%% <p>This is the format of the <tt>affiliations</tt> table. The type of the
|
|
||||||
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
|
||||||
|
|
||||||
%-record(pubsub_state,
|
|
||||||
% {stateid, items = [], affiliation = none,
|
|
||||||
% subscriptions = []}).
|
|
||||||
-record(pubsub_state,
|
|
||||||
{
|
|
||||||
stateid ,%:: {Entity::ljid(), NodeIdx::mod_pubsub:nodeIdx()},
|
|
||||||
items = [] ,%:: [ItemId::mod_pubsub:itemId()],
|
|
||||||
affiliation = 'none' ,%:: mod_pubsub:affiliation(),
|
|
||||||
subscriptions = [] %:: [{mod_pubsub:subscription(), mod_pubsub:subId()}]
|
|
||||||
}).
|
|
||||||
|
|
||||||
%% @type pubsubItem() = {pubsub_item, ItemId, Creation, Modification, Payload}
|
|
||||||
%% ItemId = {itemId(), nodeIdx()}
|
|
||||||
%% Creation = {now(), ljid()}
|
|
||||||
%% Modification = {now(), ljid()}
|
|
||||||
%% Payload = payload().
|
|
||||||
%% <p>This is the format of the <tt>published items</tt> table. The type of the
|
|
||||||
%% table is: <tt>set</tt>,<tt>disc</tt>,<tt>fragmented</tt>.</p>
|
|
||||||
%-record(pubsub_item,
|
|
||||||
% {itemid, creation = {unknown, unknown},
|
|
||||||
% modification = {unknown, unknown}, payload = []}).
|
|
||||||
|
|
||||||
-record(pubsub_item,
|
|
||||||
{
|
|
||||||
itemid ,%:: {mod_pubsub:itemId(), mod_pubsub:nodeIdx()},
|
|
||||||
creation = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
|
||||||
modification = {unknown, unknown} ,%:: {erlang:timestamp(), ljid()},
|
|
||||||
payload = [] %:: mod_pubsub:payload()
|
|
||||||
}).
|
|
||||||
|
|
||||||
%% @type pubsubSubscription() = {pubsub_subscription, SubId, Options}
|
|
||||||
%% SubId = subId()
|
|
||||||
%% Options = [nodeOption()].
|
|
||||||
%% <p>This is the format of the <tt>subscriptions</tt> table. The type of the
|
|
||||||
%% table is: <tt>set</tt>,<tt>ram/disc</tt>.</p>
|
|
||||||
%-record(pubsub_subscription, {subid, options}).
|
|
||||||
-record(pubsub_subscription,
|
|
||||||
{
|
|
||||||
subid ,%:: mod_pubsub:subId(),
|
|
||||||
options %:: [] | mod_pubsub:subOptions()
|
|
||||||
}).
|
|
||||||
|
|
||||||
%% @type pubsubLastItem() = {pubsub_last_item, NodeId, ItemId, Creation, Payload}
|
|
||||||
%% NodeId = nodeIdx()
|
|
||||||
%% ItemId = itemId()
|
|
||||||
%% Creation = {now(),ljid()}
|
|
||||||
%% Payload = payload().
|
|
||||||
%% <p>This is the format of the <tt>last items</tt> table. it stores last item payload
|
|
||||||
%% for every node</p>
|
|
||||||
%-record(pubsub_last_item,
|
|
||||||
% {nodeid, itemid, creation, payload}).
|
|
||||||
|
|
||||||
-record(pubsub_last_item,
|
|
||||||
{
|
|
||||||
nodeid ,%:: mod_pubsub:nodeIdx(),
|
|
||||||
itemid ,%:: mod_pubsub:itemId(),
|
|
||||||
creation ,%:: {erlang:timestamp(), ljid()},
|
|
||||||
payload %:: mod_pubsub:payload()
|
|
||||||
}).
|
|
|
@ -1,38 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%% File : xml.hrl
|
|
||||||
%%% Author : Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
|
||||||
%%% Purpose : XML utils
|
|
||||||
%%% Created : 1 May 2013 by Evgeniy Khramtsov <ekhramtsov@process-one.net>
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% xml, Copyright (C) 2002-2015 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., 59 Temple Place, Suite 330, Boston, MA
|
|
||||||
%%% 02111-1307 USA
|
|
||||||
%%%
|
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-record(xmlel,
|
|
||||||
{
|
|
||||||
name = <<"">> :: binary(),
|
|
||||||
attrs = [] :: [attr()],
|
|
||||||
children = [] :: [xmlel() | cdata()]
|
|
||||||
}).
|
|
||||||
|
|
||||||
-type(cdata() :: {xmlcdata, CData::binary()}).
|
|
||||||
|
|
||||||
-type(attr() :: {Name::binary(), Value::binary()}).
|
|
||||||
|
|
||||||
-type(xmlel() :: #xmlel{}).
|
|
|
@ -1,278 +0,0 @@
|
||||||
%%%----------------------------------------------------------------------
|
|
||||||
%%% File : gen_mod.erl
|
|
||||||
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
|
||||||
%%% Purpose :
|
|
||||||
%%% Purpose :
|
|
||||||
%%% Created : 24 Jan 2003 by Alexey Shchepin <alexey@process-one.net>
|
|
||||||
%%%
|
|
||||||
%%%
|
|
||||||
%%% ejabberd, Copyright (C) 2002-2015 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(gen_mod).
|
|
||||||
|
|
||||||
-author('alexey@process-one.net').
|
|
||||||
|
|
||||||
-export([start/0, start_module/2, start_module/3, stop_module/2,
|
|
||||||
stop_module_keep_config/2, get_opt/3, get_opt/4,
|
|
||||||
get_opt_host/3, db_type/1, db_type/2, get_module_opt/5,
|
|
||||||
get_module_opt_host/3, loaded_modules/1,
|
|
||||||
loaded_modules_with_opts/1, get_hosts/2,
|
|
||||||
get_module_proc/2, is_loaded/2]).
|
|
||||||
|
|
||||||
%%-export([behaviour_info/1]).
|
|
||||||
|
|
||||||
-include("ejabberd.hrl").
|
|
||||||
-include("logger.hrl").
|
|
||||||
|
|
||||||
-record(ejabberd_module,
|
|
||||||
{module_host = {undefined, <<"">>} :: {atom(), binary()},
|
|
||||||
opts = [] :: opts() | '_' | '$2'}).
|
|
||||||
|
|
||||||
-type opts() :: [{atom(), any()}].
|
|
||||||
|
|
||||||
-callback start(binary(), opts()) -> any().
|
|
||||||
-callback stop(binary()) -> any().
|
|
||||||
|
|
||||||
-export_type([opts/0]).
|
|
||||||
|
|
||||||
%%behaviour_info(callbacks) -> [{start, 2}, {stop, 1}];
|
|
||||||
%%behaviour_info(_Other) -> undefined.
|
|
||||||
|
|
||||||
start() ->
|
|
||||||
ets:new(ejabberd_modules,
|
|
||||||
[named_table, public,
|
|
||||||
{keypos, #ejabberd_module.module_host}]),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
-spec start_module(binary(), atom()) -> any().
|
|
||||||
|
|
||||||
start_module(Host, Module) ->
|
|
||||||
Modules = ejabberd_config:get_option(
|
|
||||||
{modules, Host},
|
|
||||||
fun(L) when is_list(L) -> L end, []),
|
|
||||||
case lists:keyfind(Module, 1, Modules) of
|
|
||||||
{_, Opts} ->
|
|
||||||
start_module(Host, Module, Opts);
|
|
||||||
false ->
|
|
||||||
{error, not_found_in_config}
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec start_module(binary(), atom(), opts()) -> any().
|
|
||||||
|
|
||||||
start_module(Host, Module, Opts) ->
|
|
||||||
ets:insert(ejabberd_modules,
|
|
||||||
#ejabberd_module{module_host = {Module, Host},
|
|
||||||
opts = Opts}),
|
|
||||||
try Module:start(Host, Opts) catch
|
|
||||||
Class:Reason ->
|
|
||||||
ets:delete(ejabberd_modules, {Module, Host}),
|
|
||||||
ErrorText =
|
|
||||||
io_lib:format("Problem starting the module ~p for host "
|
|
||||||
"~p ~n options: ~p~n ~p: ~p~n~p",
|
|
||||||
[Module, Host, Opts, Class, Reason,
|
|
||||||
erlang:get_stacktrace()]),
|
|
||||||
?CRITICAL_MSG(ErrorText, []),
|
|
||||||
case is_app_running(ejabberd) of
|
|
||||||
true ->
|
|
||||||
erlang:raise(Class, Reason, erlang:get_stacktrace());
|
|
||||||
false ->
|
|
||||||
?CRITICAL_MSG("ejabberd initialization was aborted "
|
|
||||||
"because a module start failed.",
|
|
||||||
[]),
|
|
||||||
timer:sleep(3000),
|
|
||||||
erlang:halt(string:substr(lists:flatten(ErrorText), 1, 199))
|
|
||||||
end
|
|
||||||
end.
|
|
||||||
|
|
||||||
is_app_running(AppName) ->
|
|
||||||
Timeout = 15000,
|
|
||||||
lists:keymember(AppName, 1,
|
|
||||||
application:which_applications(Timeout)).
|
|
||||||
|
|
||||||
-spec stop_module(binary(), atom()) -> error | {aborted, any()} | {atomic, any()}.
|
|
||||||
|
|
||||||
%% @doc Stop the module in a host, and forget its configuration.
|
|
||||||
stop_module(Host, Module) ->
|
|
||||||
case stop_module_keep_config(Host, Module) of
|
|
||||||
error -> error;
|
|
||||||
ok -> ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
%% @doc Stop the module in a host, but keep its configuration.
|
|
||||||
%% As the module configuration is kept in the Mnesia local_config table,
|
|
||||||
%% when ejabberd is restarted the module will be started again.
|
|
||||||
%% This function is useful when ejabberd is being stopped
|
|
||||||
%% and it stops all modules.
|
|
||||||
-spec stop_module_keep_config(binary(), atom()) -> error | ok.
|
|
||||||
|
|
||||||
stop_module_keep_config(Host, Module) ->
|
|
||||||
case catch Module:stop(Host) of
|
|
||||||
{'EXIT', Reason} -> ?ERROR_MSG("~p", [Reason]), error;
|
|
||||||
{wait, ProcList} when is_list(ProcList) ->
|
|
||||||
lists:foreach(fun wait_for_process/1, ProcList),
|
|
||||||
ets:delete(ejabberd_modules, {Module, Host}),
|
|
||||||
ok;
|
|
||||||
{wait, Process} ->
|
|
||||||
wait_for_process(Process),
|
|
||||||
ets:delete(ejabberd_modules, {Module, Host}),
|
|
||||||
ok;
|
|
||||||
_ -> ets:delete(ejabberd_modules, {Module, Host}), ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
wait_for_process(Process) ->
|
|
||||||
MonitorReference = erlang:monitor(process, Process),
|
|
||||||
wait_for_stop(Process, MonitorReference).
|
|
||||||
|
|
||||||
wait_for_stop(Process, MonitorReference) ->
|
|
||||||
receive
|
|
||||||
{'DOWN', MonitorReference, _Type, _Object, _Info} -> ok
|
|
||||||
after 5000 ->
|
|
||||||
catch exit(whereis(Process), kill),
|
|
||||||
wait_for_stop1(MonitorReference)
|
|
||||||
end.
|
|
||||||
|
|
||||||
wait_for_stop1(MonitorReference) ->
|
|
||||||
receive
|
|
||||||
{'DOWN', MonitorReference, _Type, _Object, _Info} -> ok
|
|
||||||
after 5000 -> ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
-type check_fun() :: fun((any()) -> any()) | {module(), atom()}.
|
|
||||||
|
|
||||||
-spec get_opt(atom(), opts(), check_fun()) -> any().
|
|
||||||
|
|
||||||
get_opt(Opt, Opts, F) ->
|
|
||||||
get_opt(Opt, Opts, F, undefined).
|
|
||||||
|
|
||||||
-spec get_opt(atom(), opts(), check_fun(), any()) -> any().
|
|
||||||
|
|
||||||
get_opt(Opt, Opts, F, Default) ->
|
|
||||||
case lists:keysearch(Opt, 1, Opts) of
|
|
||||||
false ->
|
|
||||||
Default;
|
|
||||||
{value, {_, Val}} ->
|
|
||||||
ejabberd_config:prepare_opt_val(Opt, Val, F, Default)
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec get_module_opt(global | binary(), atom(), atom(), check_fun(), any()) -> any().
|
|
||||||
|
|
||||||
get_module_opt(global, Module, Opt, F, Default) ->
|
|
||||||
Hosts = (?MYHOSTS),
|
|
||||||
[Value | Values] = lists:map(fun (Host) ->
|
|
||||||
get_module_opt(Host, Module, Opt,
|
|
||||||
F, Default)
|
|
||||||
end,
|
|
||||||
Hosts),
|
|
||||||
Same_all = lists:all(fun (Other_value) ->
|
|
||||||
Other_value == Value
|
|
||||||
end,
|
|
||||||
Values),
|
|
||||||
case Same_all of
|
|
||||||
true -> Value;
|
|
||||||
false -> Default
|
|
||||||
end;
|
|
||||||
get_module_opt(Host, Module, Opt, F, Default) ->
|
|
||||||
OptsList = ets:lookup(ejabberd_modules, {Module, Host}),
|
|
||||||
case OptsList of
|
|
||||||
[] -> Default;
|
|
||||||
[#ejabberd_module{opts = Opts} | _] ->
|
|
||||||
get_opt(Opt, Opts, F, Default)
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec get_module_opt_host(global | binary(), atom(), binary()) -> binary().
|
|
||||||
|
|
||||||
get_module_opt_host(Host, Module, Default) ->
|
|
||||||
Val = get_module_opt(Host, Module, host,
|
|
||||||
fun iolist_to_binary/1,
|
|
||||||
Default),
|
|
||||||
ejabberd_regexp:greplace(Val, <<"@HOST@">>, Host).
|
|
||||||
|
|
||||||
-spec get_opt_host(binary(), opts(), binary()) -> binary().
|
|
||||||
|
|
||||||
get_opt_host(Host, Opts, Default) ->
|
|
||||||
Val = get_opt(host, Opts, fun iolist_to_binary/1, Default),
|
|
||||||
ejabberd_regexp:greplace(Val, <<"@HOST@">>, Host).
|
|
||||||
|
|
||||||
-spec db_type(opts()) -> odbc | mnesia | riak.
|
|
||||||
|
|
||||||
db_type(Opts) ->
|
|
||||||
get_opt(db_type, Opts,
|
|
||||||
fun(odbc) -> odbc;
|
|
||||||
(internal) -> mnesia;
|
|
||||||
(mnesia) -> mnesia;
|
|
||||||
(riak) -> riak
|
|
||||||
end,
|
|
||||||
mnesia).
|
|
||||||
|
|
||||||
-spec db_type(binary(), atom()) -> odbc | mnesia | riak.
|
|
||||||
|
|
||||||
db_type(Host, Module) ->
|
|
||||||
get_module_opt(Host, Module, db_type,
|
|
||||||
fun(odbc) -> odbc;
|
|
||||||
(internal) -> mnesia;
|
|
||||||
(mnesia) -> mnesia;
|
|
||||||
(riak) -> riak
|
|
||||||
end,
|
|
||||||
mnesia).
|
|
||||||
|
|
||||||
-spec loaded_modules(binary()) -> [atom()].
|
|
||||||
|
|
||||||
loaded_modules(Host) ->
|
|
||||||
ets:select(ejabberd_modules,
|
|
||||||
[{#ejabberd_module{_ = '_', module_host = {'$1', Host}},
|
|
||||||
[], ['$1']}]).
|
|
||||||
|
|
||||||
-spec loaded_modules_with_opts(binary()) -> [{atom(), opts()}].
|
|
||||||
|
|
||||||
loaded_modules_with_opts(Host) ->
|
|
||||||
ets:select(ejabberd_modules,
|
|
||||||
[{#ejabberd_module{_ = '_', module_host = {'$1', Host},
|
|
||||||
opts = '$2'},
|
|
||||||
[], [{{'$1', '$2'}}]}]).
|
|
||||||
|
|
||||||
-spec get_hosts(opts(), binary()) -> [binary()].
|
|
||||||
|
|
||||||
get_hosts(Opts, Prefix) ->
|
|
||||||
case get_opt(hosts, Opts,
|
|
||||||
fun(Hs) -> [iolist_to_binary(H) || H <- Hs] end) of
|
|
||||||
undefined ->
|
|
||||||
case get_opt(host, Opts,
|
|
||||||
fun iolist_to_binary/1) of
|
|
||||||
undefined ->
|
|
||||||
[<<Prefix/binary, Host/binary>> || Host <- ?MYHOSTS];
|
|
||||||
Host ->
|
|
||||||
[Host]
|
|
||||||
end;
|
|
||||||
Hosts ->
|
|
||||||
Hosts
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec get_module_proc(binary(), {frontend, atom()} | atom()) -> atom().
|
|
||||||
|
|
||||||
get_module_proc(Host, {frontend, Base}) ->
|
|
||||||
get_module_proc(<<"frontend_", Host/binary>>, Base);
|
|
||||||
get_module_proc(Host, Base) ->
|
|
||||||
binary_to_atom(
|
|
||||||
<<(erlang:atom_to_binary(Base, latin1))/binary, "_", Host/binary>>,
|
|
||||||
latin1).
|
|
||||||
|
|
||||||
-spec is_loaded(binary(), atom()) -> boolean().
|
|
||||||
|
|
||||||
is_loaded(Host, Module) ->
|
|
||||||
ets:member(ejabberd_modules, {Module, Host}).
|
|
|
@ -1,279 +0,0 @@
|
||||||
%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
|
|
||||||
%%
|
|
||||||
%% This file is provided to you under the Apache License,
|
|
||||||
%% Version 2.0 (the "License"); you may not use this file
|
|
||||||
%% except in compliance with the License. You may obtain
|
|
||||||
%% a copy of the License at
|
|
||||||
%%
|
|
||||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
%%
|
|
||||||
%% Unless required by applicable law or agreed to in writing,
|
|
||||||
%% software distributed under the License is distributed on an
|
|
||||||
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
%% KIND, either express or implied. See the License for the
|
|
||||||
%% specific language governing permissions and limitations
|
|
||||||
%% under the License.
|
|
||||||
|
|
||||||
%% @doc The parse transform used for lager messages.
|
|
||||||
%% This parse transform rewrites functions calls to lager:Severity/1,2 into
|
|
||||||
%% a more complicated function that captures module, function, line, pid and
|
|
||||||
%% time as well. The entire function call is then wrapped in a case that
|
|
||||||
%% checks the lager_config 'loglevel' value, so the code isn't executed if
|
|
||||||
%% nothing wishes to consume the message.
|
|
||||||
|
|
||||||
-module(lager_transform).
|
|
||||||
|
|
||||||
-include("lager.hrl").
|
|
||||||
|
|
||||||
-export([parse_transform/2]).
|
|
||||||
|
|
||||||
%% @private
|
|
||||||
parse_transform(AST, Options) ->
|
|
||||||
TruncSize = proplists:get_value(lager_truncation_size, Options, ?DEFAULT_TRUNCATION),
|
|
||||||
Enable = proplists:get_value(lager_print_records_flag, Options, true),
|
|
||||||
put(print_records_flag, Enable),
|
|
||||||
put(truncation_size, TruncSize),
|
|
||||||
erlang:put(records, []),
|
|
||||||
%% .app file should either be in the outdir, or the same dir as the source file
|
|
||||||
guess_application(proplists:get_value(outdir, Options), hd(AST)),
|
|
||||||
walk_ast([], AST).
|
|
||||||
|
|
||||||
walk_ast(Acc, []) ->
|
|
||||||
case get(print_records_flag) of
|
|
||||||
true ->
|
|
||||||
insert_record_attribute(Acc);
|
|
||||||
false ->
|
|
||||||
lists:reverse(Acc)
|
|
||||||
end;
|
|
||||||
walk_ast(Acc, [{attribute, _, module, {Module, _PmodArgs}}=H|T]) ->
|
|
||||||
%% A wild parameterized module appears!
|
|
||||||
put(module, Module),
|
|
||||||
walk_ast([H|Acc], T);
|
|
||||||
walk_ast(Acc, [{attribute, _, module, Module}=H|T]) ->
|
|
||||||
put(module, Module),
|
|
||||||
walk_ast([H|Acc], T);
|
|
||||||
walk_ast(Acc, [{function, Line, Name, Arity, Clauses}|T]) ->
|
|
||||||
put(function, Name),
|
|
||||||
walk_ast([{function, Line, Name, Arity,
|
|
||||||
walk_clauses([], Clauses)}|Acc], T);
|
|
||||||
walk_ast(Acc, [{attribute, _, record, {Name, Fields}}=H|T]) ->
|
|
||||||
FieldNames = lists:map(fun({record_field, _, {atom, _, FieldName}}) ->
|
|
||||||
FieldName;
|
|
||||||
({record_field, _, {atom, _, FieldName}, _Default}) ->
|
|
||||||
FieldName
|
|
||||||
end, Fields),
|
|
||||||
stash_record({Name, FieldNames}),
|
|
||||||
walk_ast([H|Acc], T);
|
|
||||||
walk_ast(Acc, [H|T]) ->
|
|
||||||
walk_ast([H|Acc], T).
|
|
||||||
|
|
||||||
walk_clauses(Acc, []) ->
|
|
||||||
lists:reverse(Acc);
|
|
||||||
walk_clauses(Acc, [{clause, Line, Arguments, Guards, Body}|T]) ->
|
|
||||||
walk_clauses([{clause, Line, Arguments, Guards, walk_body([], Body)}|Acc], T).
|
|
||||||
|
|
||||||
walk_body(Acc, []) ->
|
|
||||||
lists:reverse(Acc);
|
|
||||||
walk_body(Acc, [H|T]) ->
|
|
||||||
walk_body([transform_statement(H)|Acc], T).
|
|
||||||
|
|
||||||
transform_statement({call, Line, {remote, _Line1, {atom, _Line2, lager},
|
|
||||||
{atom, _Line3, Severity}}, Arguments0} = Stmt) ->
|
|
||||||
case lists:member(Severity, ?LEVELS) of
|
|
||||||
true ->
|
|
||||||
SeverityAsInt=lager_util:level_to_num(Severity),
|
|
||||||
DefaultAttrs0 = {cons, Line, {tuple, Line, [
|
|
||||||
{atom, Line, module}, {atom, Line, get(module)}]},
|
|
||||||
{cons, Line, {tuple, Line, [
|
|
||||||
{atom, Line, function}, {atom, Line, get(function)}]},
|
|
||||||
{cons, Line, {tuple, Line, [
|
|
||||||
{atom, Line, line},
|
|
||||||
{integer, Line, Line}]},
|
|
||||||
{cons, Line, {tuple, Line, [
|
|
||||||
{atom, Line, pid},
|
|
||||||
{call, Line, {atom, Line, pid_to_list}, [
|
|
||||||
{call, Line, {atom, Line ,self}, []}]}]},
|
|
||||||
{cons, Line, {tuple, Line, [
|
|
||||||
{atom, Line, node},
|
|
||||||
{call, Line, {atom, Line, node}, []}]},
|
|
||||||
%% get the metadata with lager:md(), this will always return a list so we can use it as the tail here
|
|
||||||
{call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, md}}, []}}}}}},
|
|
||||||
%{nil, Line}}}}}}},
|
|
||||||
DefaultAttrs = case erlang:get(application) of
|
|
||||||
undefined ->
|
|
||||||
DefaultAttrs0;
|
|
||||||
App ->
|
|
||||||
%% stick the application in the attribute list
|
|
||||||
concat_lists({cons, Line, {tuple, Line, [
|
|
||||||
{atom, Line, application},
|
|
||||||
{atom, Line, App}]},
|
|
||||||
{nil, Line}}, DefaultAttrs0)
|
|
||||||
end,
|
|
||||||
{Traces, Message, Arguments} = case Arguments0 of
|
|
||||||
[Format] ->
|
|
||||||
{DefaultAttrs, Format, {atom, Line, none}};
|
|
||||||
[Arg1, Arg2] ->
|
|
||||||
%% some ambiguity here, figure out if these arguments are
|
|
||||||
%% [Format, Args] or [Attr, Format].
|
|
||||||
%% The trace attributes will be a list of tuples, so check
|
|
||||||
%% for that.
|
|
||||||
case {element(1, Arg1), Arg1} of
|
|
||||||
{_, {cons, _, {tuple, _, _}, _}} ->
|
|
||||||
{concat_lists(Arg1, DefaultAttrs),
|
|
||||||
Arg2, {atom, Line, none}};
|
|
||||||
{Type, _} when Type == var;
|
|
||||||
Type == lc;
|
|
||||||
Type == call;
|
|
||||||
Type == record_field ->
|
|
||||||
%% crap, its not a literal. look at the second
|
|
||||||
%% argument to see if it is a string
|
|
||||||
case Arg2 of
|
|
||||||
{string, _, _} ->
|
|
||||||
{concat_lists(Arg1, DefaultAttrs),
|
|
||||||
Arg2, {atom, Line, none}};
|
|
||||||
_ ->
|
|
||||||
%% not a string, going to have to guess
|
|
||||||
%% it's the argument list
|
|
||||||
{DefaultAttrs, Arg1, Arg2}
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
{DefaultAttrs, Arg1, Arg2}
|
|
||||||
end;
|
|
||||||
[Attrs, Format, Args] ->
|
|
||||||
{concat_lists(Attrs, DefaultAttrs), Format, Args}
|
|
||||||
end,
|
|
||||||
%% Generate some unique variable names so we don't accidentaly export from case clauses.
|
|
||||||
%% Note that these are not actual atoms, but the AST treats variable names as atoms.
|
|
||||||
LevelVar = make_varname("__Level", Line),
|
|
||||||
TracesVar = make_varname("__Traces", Line),
|
|
||||||
PidVar = make_varname("__Pid", Line),
|
|
||||||
%% Wrap the call to lager_dispatch log in a case that will avoid doing any work if this message is not elegible for logging
|
|
||||||
%% case {whereis(lager_event(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of
|
|
||||||
{'case', Line,
|
|
||||||
{tuple, Line,
|
|
||||||
[{call, Line, {atom, Line, whereis}, [{atom, Line, lager_event}]},
|
|
||||||
{call, Line, {remote, Line, {atom, Line, lager_config}, {atom, Line, get}}, [{atom, Line, loglevel}, {tuple, Line, [{integer, Line, 0},{nil, Line}]}]}]},
|
|
||||||
[
|
|
||||||
%% {undefined, _} -> {error, lager_not_running}
|
|
||||||
{clause, Line,
|
|
||||||
[{tuple, Line, [{atom, Line, undefined}, {var, Line, '_'}]}],
|
|
||||||
[],
|
|
||||||
%% trick the linter into avoiding a 'term constructed by not used' error:
|
|
||||||
%% (fun() -> {error, lager_not_running} end)();
|
|
||||||
[{call, Line, {'fun', Line, {clauses, [{clause, Line, [],[], [{tuple, Line, [{atom, Line, error},{atom, Line, lager_not_running}]}]}]}}, []}]},
|
|
||||||
%% If we care about the loglevel, or there's any traces installed, we have do more checking
|
|
||||||
%% {Level, Traces} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] ->
|
|
||||||
{clause, Line,
|
|
||||||
[{tuple, Line, [{var, Line, PidVar}, {tuple, Line, [{var, Line, LevelVar}, {var, Line, TracesVar}]}]}],
|
|
||||||
[[{op, Line, 'orelse',
|
|
||||||
{op, Line, '/=', {op, Line, 'band', {var, Line, LevelVar}, {integer, Line, SeverityAsInt}}, {integer, Line, 0}},
|
|
||||||
{op, Line, '/=', {var, Line, TracesVar}, {nil, Line}}}]],
|
|
||||||
[
|
|
||||||
%% do the call to lager:dispatch_log
|
|
||||||
{call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, do_log}},
|
|
||||||
[
|
|
||||||
{atom,Line,Severity},
|
|
||||||
Traces,
|
|
||||||
Message,
|
|
||||||
Arguments,
|
|
||||||
{integer, Line, get(truncation_size)},
|
|
||||||
{integer, Line, SeverityAsInt},
|
|
||||||
{var, Line, LevelVar},
|
|
||||||
{var, Line, TracesVar},
|
|
||||||
{var, Line, PidVar}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]},
|
|
||||||
%% otherwise, do nothing
|
|
||||||
%% _ -> ok
|
|
||||||
{clause, Line, [{var, Line, '_'}],[],[{atom, Line, ok}]}
|
|
||||||
]};
|
|
||||||
false ->
|
|
||||||
Stmt
|
|
||||||
end;
|
|
||||||
transform_statement({call, Line, {remote, Line1, {atom, Line2, boston_lager},
|
|
||||||
{atom, Line3, Severity}}, Arguments}) ->
|
|
||||||
NewArgs = case Arguments of
|
|
||||||
[{string, L, Msg}] -> [{string, L, re:replace(Msg, "r", "h", [{return, list}, global])}];
|
|
||||||
[{string, L, Format}, Args] -> [{string, L, re:replace(Format, "r", "h", [{return, list}, global])}, Args];
|
|
||||||
Other -> Other
|
|
||||||
end,
|
|
||||||
transform_statement({call, Line, {remote, Line1, {atom, Line2, lager},
|
|
||||||
{atom, Line3, Severity}}, NewArgs});
|
|
||||||
transform_statement(Stmt) when is_tuple(Stmt) ->
|
|
||||||
list_to_tuple(transform_statement(tuple_to_list(Stmt)));
|
|
||||||
transform_statement(Stmt) when is_list(Stmt) ->
|
|
||||||
[transform_statement(S) || S <- Stmt];
|
|
||||||
transform_statement(Stmt) ->
|
|
||||||
Stmt.
|
|
||||||
|
|
||||||
make_varname(Prefix, Line) ->
|
|
||||||
list_to_atom(Prefix ++ atom_to_list(get(module)) ++ integer_to_list(Line)).
|
|
||||||
|
|
||||||
%% concat 2 list ASTs by replacing the terminating [] in A with the contents of B
|
|
||||||
concat_lists({var, Line, _Name}=Var, B) ->
|
|
||||||
%% concatenating a var with a cons
|
|
||||||
{call, Line, {remote, Line, {atom, Line, lists},{atom, Line, flatten}},
|
|
||||||
[{cons, Line, Var, B}]};
|
|
||||||
concat_lists({lc, Line, _Body, _Generator} = LC, B) ->
|
|
||||||
%% concatenating a LC with a cons
|
|
||||||
{call, Line, {remote, Line, {atom, Line, lists},{atom, Line, flatten}},
|
|
||||||
[{cons, Line, LC, B}]};
|
|
||||||
concat_lists({call, Line, _Function, _Args} = Call, B) ->
|
|
||||||
%% concatenating a call with a cons
|
|
||||||
{call, Line, {remote, Line, {atom, Line, lists},{atom, Line, flatten}},
|
|
||||||
[{cons, Line, Call, B}]};
|
|
||||||
concat_lists({record_field, Line, _Var, _Record, _Field} = Rec, B) ->
|
|
||||||
%% concatenating a record_field with a cons
|
|
||||||
{call, Line, {remote, Line, {atom, Line, lists},{atom, Line, flatten}},
|
|
||||||
[{cons, Line, Rec, B}]};
|
|
||||||
concat_lists({nil, _Line}, B) ->
|
|
||||||
B;
|
|
||||||
concat_lists({cons, Line, Element, Tail}, B) ->
|
|
||||||
{cons, Line, Element, concat_lists(Tail, B)}.
|
|
||||||
|
|
||||||
stash_record(Record) ->
|
|
||||||
Records = case erlang:get(records) of
|
|
||||||
undefined ->
|
|
||||||
[];
|
|
||||||
R ->
|
|
||||||
R
|
|
||||||
end,
|
|
||||||
erlang:put(records, [Record|Records]).
|
|
||||||
|
|
||||||
insert_record_attribute(AST) ->
|
|
||||||
lists:foldl(fun({attribute, Line, module, _}=E, Acc) ->
|
|
||||||
[E, {attribute, Line, lager_records, erlang:get(records)}|Acc];
|
|
||||||
(E, Acc) ->
|
|
||||||
[E|Acc]
|
|
||||||
end, [], AST).
|
|
||||||
|
|
||||||
guess_application(Dirname, Attr) when Dirname /= undefined ->
|
|
||||||
case find_app_file(Dirname) of
|
|
||||||
no_idea ->
|
|
||||||
%% try it based on source file directory (app.src most likely)
|
|
||||||
guess_application(undefined, Attr);
|
|
||||||
_ ->
|
|
||||||
ok
|
|
||||||
end;
|
|
||||||
guess_application(undefined, {attribute, _, file, {Filename, _}}) ->
|
|
||||||
Dir = filename:dirname(Filename),
|
|
||||||
find_app_file(Dir);
|
|
||||||
guess_application(_, _) ->
|
|
||||||
ok.
|
|
||||||
|
|
||||||
find_app_file(Dir) ->
|
|
||||||
case filelib:wildcard(Dir++"/*.{app,app.src}") of
|
|
||||||
[] ->
|
|
||||||
no_idea;
|
|
||||||
[File] ->
|
|
||||||
case file:consult(File) of
|
|
||||||
{ok, [{application, Appname, _Attributes}|_]} ->
|
|
||||||
erlang:put(application, Appname);
|
|
||||||
_ ->
|
|
||||||
no_idea
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
%% multiple files, uh oh
|
|
||||||
no_idea
|
|
||||||
end.
|
|
|
@ -1,710 +0,0 @@
|
||||||
%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
|
|
||||||
%%
|
|
||||||
%% This file is provided to you under the Apache License,
|
|
||||||
%% Version 2.0 (the "License"); you may not use this file
|
|
||||||
%% except in compliance with the License. You may obtain
|
|
||||||
%% a copy of the License at
|
|
||||||
%%
|
|
||||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
%%
|
|
||||||
%% Unless required by applicable law or agreed to in writing,
|
|
||||||
%% software distributed under the License is distributed on an
|
|
||||||
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
%% KIND, either express or implied. See the License for the
|
|
||||||
%% specific language governing permissions and limitations
|
|
||||||
%% under the License.
|
|
||||||
|
|
||||||
-module(lager_util).
|
|
||||||
|
|
||||||
-include_lib("kernel/include/file.hrl").
|
|
||||||
|
|
||||||
-export([levels/0, level_to_num/1, num_to_level/1, config_to_mask/1, config_to_levels/1, mask_to_levels/1,
|
|
||||||
open_logfile/2, ensure_logfile/4, rotate_logfile/2, format_time/0, format_time/1,
|
|
||||||
localtime_ms/0, localtime_ms/1, maybe_utc/1, parse_rotation_date_spec/1,
|
|
||||||
calculate_next_rotation/1, validate_trace/1, check_traces/4, is_loggable/3,
|
|
||||||
trace_filter/1, trace_filter/2]).
|
|
||||||
|
|
||||||
-ifdef(TEST).
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
-endif.
|
|
||||||
|
|
||||||
-include("lager.hrl").
|
|
||||||
|
|
||||||
levels() ->
|
|
||||||
[debug, info, notice, warning, error, critical, alert, emergency, none].
|
|
||||||
|
|
||||||
level_to_num(debug) -> ?DEBUG;
|
|
||||||
level_to_num(info) -> ?INFO;
|
|
||||||
level_to_num(notice) -> ?NOTICE;
|
|
||||||
level_to_num(warning) -> ?WARNING;
|
|
||||||
level_to_num(error) -> ?ERROR;
|
|
||||||
level_to_num(critical) -> ?CRITICAL;
|
|
||||||
level_to_num(alert) -> ?ALERT;
|
|
||||||
level_to_num(emergency) -> ?EMERGENCY;
|
|
||||||
level_to_num(none) -> ?LOG_NONE.
|
|
||||||
|
|
||||||
num_to_level(?DEBUG) -> debug;
|
|
||||||
num_to_level(?INFO) -> info;
|
|
||||||
num_to_level(?NOTICE) -> notice;
|
|
||||||
num_to_level(?WARNING) -> warning;
|
|
||||||
num_to_level(?ERROR) -> error;
|
|
||||||
num_to_level(?CRITICAL) -> critical;
|
|
||||||
num_to_level(?ALERT) -> alert;
|
|
||||||
num_to_level(?EMERGENCY) -> emergency;
|
|
||||||
num_to_level(?LOG_NONE) -> none.
|
|
||||||
|
|
||||||
-spec config_to_mask(atom()|string()) -> {'mask', integer()}.
|
|
||||||
config_to_mask(Conf) ->
|
|
||||||
Levels = config_to_levels(Conf),
|
|
||||||
{mask, lists:foldl(fun(Level, Acc) ->
|
|
||||||
level_to_num(Level) bor Acc
|
|
||||||
end, 0, Levels)}.
|
|
||||||
|
|
||||||
-spec mask_to_levels(non_neg_integer()) -> [lager:log_level()].
|
|
||||||
mask_to_levels(Mask) ->
|
|
||||||
mask_to_levels(Mask, levels(), []).
|
|
||||||
|
|
||||||
mask_to_levels(_Mask, [], Acc) ->
|
|
||||||
lists:reverse(Acc);
|
|
||||||
mask_to_levels(Mask, [Level|Levels], Acc) ->
|
|
||||||
NewAcc = case (level_to_num(Level) band Mask) /= 0 of
|
|
||||||
true ->
|
|
||||||
[Level|Acc];
|
|
||||||
false ->
|
|
||||||
Acc
|
|
||||||
end,
|
|
||||||
mask_to_levels(Mask, Levels, NewAcc).
|
|
||||||
|
|
||||||
-spec config_to_levels(atom()|string()) -> [lager:log_level()].
|
|
||||||
config_to_levels(Conf) when is_atom(Conf) ->
|
|
||||||
config_to_levels(atom_to_list(Conf));
|
|
||||||
config_to_levels([$! | Rest]) ->
|
|
||||||
levels() -- config_to_levels(Rest);
|
|
||||||
config_to_levels([$=, $< | Rest]) ->
|
|
||||||
[_|Levels] = config_to_levels_int(Rest),
|
|
||||||
lists:filter(fun(E) -> not lists:member(E, Levels) end, levels());
|
|
||||||
config_to_levels([$<, $= | Rest]) ->
|
|
||||||
[_|Levels] = config_to_levels_int(Rest),
|
|
||||||
lists:filter(fun(E) -> not lists:member(E, Levels) end, levels());
|
|
||||||
config_to_levels([$>, $= | Rest]) ->
|
|
||||||
config_to_levels_int(Rest);
|
|
||||||
config_to_levels([$=, $> | Rest]) ->
|
|
||||||
config_to_levels_int(Rest);
|
|
||||||
config_to_levels([$= | Rest]) ->
|
|
||||||
[level_to_atom(Rest)];
|
|
||||||
config_to_levels([$< | Rest]) ->
|
|
||||||
Levels = config_to_levels_int(Rest),
|
|
||||||
lists:filter(fun(E) -> not lists:member(E, Levels) end, levels());
|
|
||||||
config_to_levels([$> | Rest]) ->
|
|
||||||
[_|Levels] = config_to_levels_int(Rest),
|
|
||||||
lists:filter(fun(E) -> lists:member(E, Levels) end, levels());
|
|
||||||
config_to_levels(Conf) ->
|
|
||||||
config_to_levels_int(Conf).
|
|
||||||
|
|
||||||
%% internal function to break the recursion loop
|
|
||||||
config_to_levels_int(Conf) ->
|
|
||||||
Level = level_to_atom(Conf),
|
|
||||||
lists:dropwhile(fun(E) -> E /= Level end, levels()).
|
|
||||||
|
|
||||||
level_to_atom(String) ->
|
|
||||||
Levels = levels(),
|
|
||||||
try list_to_existing_atom(String) of
|
|
||||||
Atom ->
|
|
||||||
case lists:member(Atom, Levels) of
|
|
||||||
true ->
|
|
||||||
Atom;
|
|
||||||
false ->
|
|
||||||
erlang:error(badarg)
|
|
||||||
end
|
|
||||||
catch
|
|
||||||
_:_ ->
|
|
||||||
erlang:error(badarg)
|
|
||||||
end.
|
|
||||||
|
|
||||||
open_logfile(Name, Buffer) ->
|
|
||||||
case filelib:ensure_dir(Name) of
|
|
||||||
ok ->
|
|
||||||
Options = [append, raw] ++
|
|
||||||
case Buffer of
|
|
||||||
{Size, Interval} when is_integer(Interval), Interval >= 0, is_integer(Size), Size >= 0 ->
|
|
||||||
[{delayed_write, Size, Interval}];
|
|
||||||
_ -> []
|
|
||||||
end,
|
|
||||||
case file:open(Name, Options) of
|
|
||||||
{ok, FD} ->
|
|
||||||
case file:read_file_info(Name) of
|
|
||||||
{ok, FInfo} ->
|
|
||||||
Inode = FInfo#file_info.inode,
|
|
||||||
{ok, {FD, Inode, FInfo#file_info.size}};
|
|
||||||
X -> X
|
|
||||||
end;
|
|
||||||
Y -> Y
|
|
||||||
end;
|
|
||||||
Z -> Z
|
|
||||||
end.
|
|
||||||
|
|
||||||
ensure_logfile(Name, FD, Inode, Buffer) ->
|
|
||||||
case file:read_file_info(Name) of
|
|
||||||
{ok, FInfo} ->
|
|
||||||
Inode2 = FInfo#file_info.inode,
|
|
||||||
case Inode == Inode2 of
|
|
||||||
true ->
|
|
||||||
{ok, {FD, Inode, FInfo#file_info.size}};
|
|
||||||
false ->
|
|
||||||
%% delayed write can cause file:close not to do a close
|
|
||||||
_ = file:close(FD),
|
|
||||||
_ = file:close(FD),
|
|
||||||
case open_logfile(Name, Buffer) of
|
|
||||||
{ok, {FD2, Inode3, Size}} ->
|
|
||||||
%% inode changed, file was probably moved and
|
|
||||||
%% recreated
|
|
||||||
{ok, {FD2, Inode3, Size}};
|
|
||||||
Error ->
|
|
||||||
Error
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
_ ->
|
|
||||||
%% delayed write can cause file:close not to do a close
|
|
||||||
_ = file:close(FD),
|
|
||||||
_ = file:close(FD),
|
|
||||||
case open_logfile(Name, Buffer) of
|
|
||||||
{ok, {FD2, Inode3, Size}} ->
|
|
||||||
%% file was removed
|
|
||||||
{ok, {FD2, Inode3, Size}};
|
|
||||||
Error ->
|
|
||||||
Error
|
|
||||||
end
|
|
||||||
end.
|
|
||||||
|
|
||||||
%% returns localtime with milliseconds included
|
|
||||||
localtime_ms() ->
|
|
||||||
Now = os:timestamp(),
|
|
||||||
localtime_ms(Now).
|
|
||||||
|
|
||||||
localtime_ms(Now) ->
|
|
||||||
{_, _, Micro} = Now,
|
|
||||||
{Date, {Hours, Minutes, Seconds}} = calendar:now_to_local_time(Now),
|
|
||||||
{Date, {Hours, Minutes, Seconds, Micro div 1000 rem 1000}}.
|
|
||||||
|
|
||||||
|
|
||||||
maybe_utc({Date, {H, M, S, Ms}}) ->
|
|
||||||
case lager_stdlib:maybe_utc({Date, {H, M, S}}) of
|
|
||||||
{utc, {Date1, {H1, M1, S1}}} ->
|
|
||||||
{utc, {Date1, {H1, M1, S1, Ms}}};
|
|
||||||
{Date1, {H1, M1, S1}} ->
|
|
||||||
{Date1, {H1, M1, S1, Ms}}
|
|
||||||
end.
|
|
||||||
|
|
||||||
%% renames failing are OK
|
|
||||||
rotate_logfile(File, 0) ->
|
|
||||||
file:delete(File);
|
|
||||||
rotate_logfile(File, 1) ->
|
|
||||||
case file:rename(File, File++".0") of
|
|
||||||
ok ->
|
|
||||||
ok;
|
|
||||||
_ ->
|
|
||||||
rotate_logfile(File, 0)
|
|
||||||
end;
|
|
||||||
rotate_logfile(File, Count) ->
|
|
||||||
_ = file:rename(File ++ "." ++ integer_to_list(Count - 2), File ++ "." ++ integer_to_list(Count - 1)),
|
|
||||||
rotate_logfile(File, Count - 1).
|
|
||||||
|
|
||||||
format_time() ->
|
|
||||||
format_time(maybe_utc(localtime_ms())).
|
|
||||||
|
|
||||||
format_time({utc, {{Y, M, D}, {H, Mi, S, Ms}}}) ->
|
|
||||||
{[integer_to_list(Y), $-, i2l(M), $-, i2l(D)],
|
|
||||||
[i2l(H), $:, i2l(Mi), $:, i2l(S), $., i3l(Ms), $ , $U, $T, $C]};
|
|
||||||
format_time({{Y, M, D}, {H, Mi, S, Ms}}) ->
|
|
||||||
{[integer_to_list(Y), $-, i2l(M), $-, i2l(D)],
|
|
||||||
[i2l(H), $:, i2l(Mi), $:, i2l(S), $., i3l(Ms)]};
|
|
||||||
format_time({utc, {{Y, M, D}, {H, Mi, S}}}) ->
|
|
||||||
{[integer_to_list(Y), $-, i2l(M), $-, i2l(D)],
|
|
||||||
[i2l(H), $:, i2l(Mi), $:, i2l(S), $ , $U, $T, $C]};
|
|
||||||
format_time({{Y, M, D}, {H, Mi, S}}) ->
|
|
||||||
{[integer_to_list(Y), $-, i2l(M), $-, i2l(D)],
|
|
||||||
[i2l(H), $:, i2l(Mi), $:, i2l(S)]}.
|
|
||||||
|
|
||||||
parse_rotation_day_spec([], Res) ->
|
|
||||||
{ok, Res ++ [{hour, 0}]};
|
|
||||||
parse_rotation_day_spec([$D, D1, D2], Res) ->
|
|
||||||
case list_to_integer([D1, D2]) of
|
|
||||||
X when X >= 0, X =< 23 ->
|
|
||||||
{ok, Res ++ [{hour, X}]};
|
|
||||||
_ ->
|
|
||||||
{error, invalid_date_spec}
|
|
||||||
end;
|
|
||||||
parse_rotation_day_spec([$D, D], Res) when D >= $0, D =< $9 ->
|
|
||||||
{ok, Res ++ [{hour, D - 48}]};
|
|
||||||
parse_rotation_day_spec(_, _) ->
|
|
||||||
{error, invalid_date_spec}.
|
|
||||||
|
|
||||||
parse_rotation_date_spec([$$, $W, W|T]) when W >= $0, W =< $6 ->
|
|
||||||
Week = W - 48,
|
|
||||||
parse_rotation_day_spec(T, [{day, Week}]);
|
|
||||||
parse_rotation_date_spec([$$, $M, L|T]) when L == $L; L == $l ->
|
|
||||||
%% last day in month.
|
|
||||||
parse_rotation_day_spec(T, [{date, last}]);
|
|
||||||
parse_rotation_date_spec([$$, $M, M1, M2|[$D|_]=T]) ->
|
|
||||||
case list_to_integer([M1, M2]) of
|
|
||||||
X when X >= 1, X =< 31 ->
|
|
||||||
parse_rotation_day_spec(T, [{date, X}]);
|
|
||||||
_ ->
|
|
||||||
{error, invalid_date_spec}
|
|
||||||
end;
|
|
||||||
parse_rotation_date_spec([$$, $M, M|[$D|_]=T]) ->
|
|
||||||
parse_rotation_day_spec(T, [{date, M - 48}]);
|
|
||||||
parse_rotation_date_spec([$$, $M, M1, M2]) ->
|
|
||||||
case list_to_integer([M1, M2]) of
|
|
||||||
X when X >= 1, X =< 31 ->
|
|
||||||
{ok, [{date, X}, {hour, 0}]};
|
|
||||||
_ ->
|
|
||||||
{error, invalid_date_spec}
|
|
||||||
end;
|
|
||||||
parse_rotation_date_spec([$$, $M, M]) ->
|
|
||||||
{ok, [{date, M - 48}, {hour, 0}]};
|
|
||||||
parse_rotation_date_spec([$$|X]) when X /= [] ->
|
|
||||||
parse_rotation_day_spec(X, []);
|
|
||||||
parse_rotation_date_spec(_) ->
|
|
||||||
{error, invalid_date_spec}.
|
|
||||||
|
|
||||||
calculate_next_rotation(Spec) ->
|
|
||||||
Now = calendar:local_time(),
|
|
||||||
Later = calculate_next_rotation(Spec, Now),
|
|
||||||
calendar:datetime_to_gregorian_seconds(Later) -
|
|
||||||
calendar:datetime_to_gregorian_seconds(Now).
|
|
||||||
|
|
||||||
calculate_next_rotation([], Now) ->
|
|
||||||
Now;
|
|
||||||
calculate_next_rotation([{hour, X}|T], {{_, _, _}, {Hour, _, _}} = Now) when Hour < X ->
|
|
||||||
%% rotation is today, sometime
|
|
||||||
NewNow = setelement(2, Now, {X, 0, 0}),
|
|
||||||
calculate_next_rotation(T, NewNow);
|
|
||||||
calculate_next_rotation([{hour, X}|T], {{_, _, _}, _} = Now) ->
|
|
||||||
%% rotation is not today
|
|
||||||
Seconds = calendar:datetime_to_gregorian_seconds(Now) + 86400,
|
|
||||||
DateTime = calendar:gregorian_seconds_to_datetime(Seconds),
|
|
||||||
NewNow = setelement(2, DateTime, {X, 0, 0}),
|
|
||||||
calculate_next_rotation(T, NewNow);
|
|
||||||
calculate_next_rotation([{day, Day}|T], {Date, _Time} = Now) ->
|
|
||||||
DoW = calendar:day_of_the_week(Date),
|
|
||||||
AdjustedDay = case Day of
|
|
||||||
0 -> 7;
|
|
||||||
X -> X
|
|
||||||
end,
|
|
||||||
case AdjustedDay of
|
|
||||||
DoW -> %% rotation is today
|
|
||||||
OldDate = element(1, Now),
|
|
||||||
case calculate_next_rotation(T, Now) of
|
|
||||||
{OldDate, _} = NewNow -> NewNow;
|
|
||||||
{NewDate, _} ->
|
|
||||||
%% rotation *isn't* today! rerun the calculation
|
|
||||||
NewNow = {NewDate, {0, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, Day}|T], NewNow)
|
|
||||||
end;
|
|
||||||
Y when Y > DoW -> %% rotation is later this week
|
|
||||||
PlusDays = Y - DoW,
|
|
||||||
Seconds = calendar:datetime_to_gregorian_seconds(Now) + (86400 * PlusDays),
|
|
||||||
{NewDate, _} = calendar:gregorian_seconds_to_datetime(Seconds),
|
|
||||||
NewNow = {NewDate, {0, 0, 0}},
|
|
||||||
calculate_next_rotation(T, NewNow);
|
|
||||||
Y when Y < DoW -> %% rotation is next week
|
|
||||||
PlusDays = ((7 - DoW) + Y),
|
|
||||||
Seconds = calendar:datetime_to_gregorian_seconds(Now) + (86400 * PlusDays),
|
|
||||||
{NewDate, _} = calendar:gregorian_seconds_to_datetime(Seconds),
|
|
||||||
NewNow = {NewDate, {0, 0, 0}},
|
|
||||||
calculate_next_rotation(T, NewNow)
|
|
||||||
end;
|
|
||||||
calculate_next_rotation([{date, last}|T], {{Year, Month, Day}, _} = Now) ->
|
|
||||||
Last = calendar:last_day_of_the_month(Year, Month),
|
|
||||||
case Last == Day of
|
|
||||||
true -> %% doing rotation today
|
|
||||||
OldDate = element(1, Now),
|
|
||||||
case calculate_next_rotation(T, Now) of
|
|
||||||
{OldDate, _} = NewNow -> NewNow;
|
|
||||||
{NewDate, _} ->
|
|
||||||
%% rotation *isn't* today! rerun the calculation
|
|
||||||
NewNow = {NewDate, {0, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, last}|T], NewNow)
|
|
||||||
end;
|
|
||||||
false ->
|
|
||||||
NewNow = setelement(1, Now, {Year, Month, Last}),
|
|
||||||
calculate_next_rotation(T, NewNow)
|
|
||||||
end;
|
|
||||||
calculate_next_rotation([{date, Date}|T], {{_, _, Date}, _} = Now) ->
|
|
||||||
%% rotation is today
|
|
||||||
OldDate = element(1, Now),
|
|
||||||
case calculate_next_rotation(T, Now) of
|
|
||||||
{OldDate, _} = NewNow -> NewNow;
|
|
||||||
{NewDate, _} ->
|
|
||||||
%% rotation *isn't* today! rerun the calculation
|
|
||||||
NewNow = setelement(1, Now, NewDate),
|
|
||||||
calculate_next_rotation([{date, Date}|T], NewNow)
|
|
||||||
end;
|
|
||||||
calculate_next_rotation([{date, Date}|T], {{Year, Month, Day}, _} = Now) ->
|
|
||||||
PlusDays = case Date of
|
|
||||||
X when X < Day -> %% rotation is next month
|
|
||||||
Last = calendar:last_day_of_the_month(Year, Month),
|
|
||||||
(Last - Day);
|
|
||||||
X when X > Day -> %% rotation is later this month
|
|
||||||
X - Day
|
|
||||||
end,
|
|
||||||
Seconds = calendar:datetime_to_gregorian_seconds(Now) + (86400 * PlusDays),
|
|
||||||
NewNow = calendar:gregorian_seconds_to_datetime(Seconds),
|
|
||||||
calculate_next_rotation(T, NewNow).
|
|
||||||
|
|
||||||
-spec trace_filter(Query :: 'none' | [tuple()]) -> {ok, any()}.
|
|
||||||
trace_filter(Query) ->
|
|
||||||
trace_filter(?DEFAULT_TRACER, Query).
|
|
||||||
|
|
||||||
%% TODO: Support multiple trace modules
|
|
||||||
%-spec trace_filter(Module :: atom(), Query :: 'none' | [tuple()]) -> {ok, any()}.
|
|
||||||
trace_filter(Module, Query) when Query == none; Query == [] ->
|
|
||||||
{ok, _} = glc:compile(Module, glc:null(false));
|
|
||||||
trace_filter(Module, Query) when is_list(Query) ->
|
|
||||||
{ok, _} = glc:compile(Module, glc_lib:reduce(trace_any(Query))).
|
|
||||||
|
|
||||||
validate_trace({Filter, Level, {Destination, ID}}) when is_tuple(Filter); is_list(Filter), is_atom(Level), is_atom(Destination) ->
|
|
||||||
case validate_trace({Filter, Level, Destination}) of
|
|
||||||
{ok, {F, L, D}} ->
|
|
||||||
{ok, {F, L, {D, ID}}};
|
|
||||||
Error ->
|
|
||||||
Error
|
|
||||||
end;
|
|
||||||
validate_trace({Filter, Level, Destination}) when is_tuple(Filter); is_list(Filter), is_atom(Level), is_atom(Destination) ->
|
|
||||||
ValidFilter = validate_trace_filter(Filter),
|
|
||||||
try config_to_mask(Level) of
|
|
||||||
_ when not ValidFilter ->
|
|
||||||
{error, invalid_trace};
|
|
||||||
L when is_list(Filter) ->
|
|
||||||
{ok, {trace_all(Filter), L, Destination}};
|
|
||||||
L ->
|
|
||||||
{ok, {Filter, L, Destination}}
|
|
||||||
catch
|
|
||||||
_:_ ->
|
|
||||||
{error, invalid_level}
|
|
||||||
end;
|
|
||||||
validate_trace(_) ->
|
|
||||||
{error, invalid_trace}.
|
|
||||||
|
|
||||||
validate_trace_filter(Filter) when is_tuple(Filter), is_atom(element(1, Filter)) =:= false ->
|
|
||||||
false;
|
|
||||||
validate_trace_filter(Filter) ->
|
|
||||||
case lists:all(fun({Key, '*'}) when is_atom(Key) -> true;
|
|
||||||
({Key, '!'}) when is_atom(Key) -> true;
|
|
||||||
({Key, _Value}) when is_atom(Key) -> true;
|
|
||||||
({Key, '=', _Value}) when is_atom(Key) -> true;
|
|
||||||
({Key, '<', _Value}) when is_atom(Key) -> true;
|
|
||||||
({Key, '>', _Value}) when is_atom(Key) -> true;
|
|
||||||
(_) -> false end, Filter) of
|
|
||||||
true ->
|
|
||||||
true;
|
|
||||||
_ ->
|
|
||||||
false
|
|
||||||
end.
|
|
||||||
|
|
||||||
trace_all(Query) ->
|
|
||||||
glc:all(trace_acc(Query)).
|
|
||||||
|
|
||||||
trace_any(Query) ->
|
|
||||||
glc:any(Query).
|
|
||||||
|
|
||||||
trace_acc(Query) ->
|
|
||||||
trace_acc(Query, []).
|
|
||||||
|
|
||||||
trace_acc([], Acc) ->
|
|
||||||
lists:reverse(Acc);
|
|
||||||
trace_acc([{Key, '*'}|T], Acc) ->
|
|
||||||
trace_acc(T, [glc:wc(Key)|Acc]);
|
|
||||||
trace_acc([{Key, '!'}|T], Acc) ->
|
|
||||||
trace_acc(T, [glc:nf(Key)|Acc]);
|
|
||||||
trace_acc([{Key, Val}|T], Acc) ->
|
|
||||||
trace_acc(T, [glc:eq(Key, Val)|Acc]);
|
|
||||||
trace_acc([{Key, '=', Val}|T], Acc) ->
|
|
||||||
trace_acc(T, [glc:eq(Key, Val)|Acc]);
|
|
||||||
trace_acc([{Key, '>', Val}|T], Acc) ->
|
|
||||||
trace_acc(T, [glc:gt(Key, Val)|Acc]);
|
|
||||||
trace_acc([{Key, '<', Val}|T], Acc) ->
|
|
||||||
trace_acc(T, [glc:lt(Key, Val)|Acc]).
|
|
||||||
|
|
||||||
|
|
||||||
check_traces(_, _, [], Acc) ->
|
|
||||||
lists:flatten(Acc);
|
|
||||||
check_traces(Attrs, Level, [{_, {mask, FilterLevel}, _}|Flows], Acc) when (Level band FilterLevel) == 0 ->
|
|
||||||
check_traces(Attrs, Level, Flows, Acc);
|
|
||||||
check_traces(Attrs, Level, [{Filter, _, _}|Flows], Acc) when length(Attrs) < length(Filter) ->
|
|
||||||
check_traces(Attrs, Level, Flows, Acc);
|
|
||||||
check_traces(Attrs, Level, [Flow|Flows], Acc) ->
|
|
||||||
check_traces(Attrs, Level, Flows, [check_trace(Attrs, Flow)|Acc]).
|
|
||||||
|
|
||||||
check_trace(Attrs, {Filter, _Level, Dest}) when is_list(Filter) ->
|
|
||||||
check_trace(Attrs, {trace_all(Filter), _Level, Dest});
|
|
||||||
|
|
||||||
check_trace(Attrs, {Filter, _Level, Dest}) when is_tuple(Filter) ->
|
|
||||||
Made = gre:make(Attrs, [list]),
|
|
||||||
glc:handle(?DEFAULT_TRACER, Made),
|
|
||||||
Match = glc_lib:matches(Filter, Made),
|
|
||||||
case Match of
|
|
||||||
true ->
|
|
||||||
Dest;
|
|
||||||
false ->
|
|
||||||
[]
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec is_loggable(lager_msg:lager_msg(), non_neg_integer()|{'mask', non_neg_integer()}, term()) -> boolean().
|
|
||||||
is_loggable(Msg, {mask, Mask}, MyName) ->
|
|
||||||
%% using syslog style comparison flags
|
|
||||||
%S = lager_msg:severity_as_int(Msg),
|
|
||||||
%?debugFmt("comparing masks ~.2B and ~.2B -> ~p~n", [S, Mask, S band Mask]),
|
|
||||||
(lager_msg:severity_as_int(Msg) band Mask) /= 0 orelse
|
|
||||||
lists:member(MyName, lager_msg:destinations(Msg));
|
|
||||||
is_loggable(Msg ,SeverityThreshold,MyName) ->
|
|
||||||
lager_msg:severity_as_int(Msg) =< SeverityThreshold orelse
|
|
||||||
lists:member(MyName, lager_msg:destinations(Msg)).
|
|
||||||
|
|
||||||
i2l(I) when I < 10 -> [$0, $0+I];
|
|
||||||
i2l(I) -> integer_to_list(I).
|
|
||||||
i3l(I) when I < 100 -> [$0 | i2l(I)];
|
|
||||||
i3l(I) -> integer_to_list(I).
|
|
||||||
|
|
||||||
-ifdef(TEST).
|
|
||||||
|
|
||||||
parse_test() ->
|
|
||||||
?assertEqual({ok, [{hour, 0}]}, parse_rotation_date_spec("$D0")),
|
|
||||||
?assertEqual({ok, [{hour, 23}]}, parse_rotation_date_spec("$D23")),
|
|
||||||
?assertEqual({ok, [{day, 0}, {hour, 23}]}, parse_rotation_date_spec("$W0D23")),
|
|
||||||
?assertEqual({ok, [{day, 5}, {hour, 16}]}, parse_rotation_date_spec("$W5D16")),
|
|
||||||
?assertEqual({ok, [{date, 1}, {hour, 0}]}, parse_rotation_date_spec("$M1D0")),
|
|
||||||
?assertEqual({ok, [{date, 5}, {hour, 6}]}, parse_rotation_date_spec("$M5D6")),
|
|
||||||
?assertEqual({ok, [{date, 5}, {hour, 0}]}, parse_rotation_date_spec("$M5")),
|
|
||||||
?assertEqual({ok, [{date, 31}, {hour, 0}]}, parse_rotation_date_spec("$M31")),
|
|
||||||
?assertEqual({ok, [{date, 31}, {hour, 1}]}, parse_rotation_date_spec("$M31D1")),
|
|
||||||
?assertEqual({ok, [{date, last}, {hour, 0}]}, parse_rotation_date_spec("$ML")),
|
|
||||||
?assertEqual({ok, [{date, last}, {hour, 0}]}, parse_rotation_date_spec("$Ml")),
|
|
||||||
?assertEqual({ok, [{day, 5}, {hour, 0}]}, parse_rotation_date_spec("$W5")),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
parse_fail_test() ->
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$D")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$D24")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$W7")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$W7D1")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$M32")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$M32D1")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$D15M5")),
|
|
||||||
?assertEqual({error, invalid_date_spec}, parse_rotation_date_spec("$M5W5")),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
rotation_calculation_test() ->
|
|
||||||
?assertMatch({{2000, 1, 2}, {0, 0, 0}},
|
|
||||||
calculate_next_rotation([{hour, 0}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 1}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{hour, 16}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 2}, {12, 0, 0}},
|
|
||||||
calculate_next_rotation([{hour, 12}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, 1}, {hour, 12}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, 1}, {hour, 12}], {{2000, 1, 15}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, 1}, {hour, 12}], {{2000, 1, 2}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, 1}, {hour, 12}], {{2000, 1, 31}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 1}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, 1}, {hour, 16}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 15}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, 15}, {hour, 16}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 31}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, last}, {hour, 16}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 31}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, last}, {hour, 16}], {{2000, 1, 31}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 2, 29}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, last}, {hour, 16}], {{2000, 1, 31}, {17, 34, 43}})),
|
|
||||||
?assertMatch({{2001, 2, 28}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{date, last}, {hour, 16}], {{2001, 1, 31}, {17, 34, 43}})),
|
|
||||||
|
|
||||||
?assertMatch({{2000, 1, 1}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 6}, {hour, 16}], {{2000, 1, 1}, {12, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 8}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 6}, {hour, 16}], {{2000, 1, 1}, {17, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 7}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 5}, {hour, 16}], {{2000, 1, 1}, {17, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 3}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 1}, {hour, 16}], {{2000, 1, 1}, {17, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 2}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 0}, {hour, 16}], {{2000, 1, 1}, {17, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 1, 9}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 0}, {hour, 16}], {{2000, 1, 2}, {17, 34, 43}})),
|
|
||||||
?assertMatch({{2000, 2, 3}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 4}, {hour, 16}], {{2000, 1, 29}, {17, 34, 43}})),
|
|
||||||
|
|
||||||
?assertMatch({{2000, 1, 7}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 5}, {hour, 16}], {{2000, 1, 3}, {17, 34, 43}})),
|
|
||||||
|
|
||||||
?assertMatch({{2000, 1, 3}, {16, 0, 0}},
|
|
||||||
calculate_next_rotation([{day, 1}, {hour, 16}], {{1999, 12, 28}, {17, 34, 43}})),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
rotate_file_test() ->
|
|
||||||
file:delete("rotation.log"),
|
|
||||||
[file:delete(["rotation.log.", integer_to_list(N)]) || N <- lists:seq(0, 9)],
|
|
||||||
[begin
|
|
||||||
file:write_file("rotation.log", integer_to_list(N)),
|
|
||||||
Count = case N > 10 of
|
|
||||||
true -> 10;
|
|
||||||
_ -> N
|
|
||||||
end,
|
|
||||||
[begin
|
|
||||||
FileName = ["rotation.log.", integer_to_list(M)],
|
|
||||||
?assert(filelib:is_regular(FileName)),
|
|
||||||
%% check the expected value is in the file
|
|
||||||
Number = list_to_binary(integer_to_list(N - M - 1)),
|
|
||||||
?assertEqual({ok, Number}, file:read_file(FileName))
|
|
||||||
end
|
|
||||||
|| M <- lists:seq(0, Count-1)],
|
|
||||||
rotate_logfile("rotation.log", 10)
|
|
||||||
end || N <- lists:seq(0, 20)].
|
|
||||||
|
|
||||||
rotate_file_fail_test() ->
|
|
||||||
%% make sure the directory exists
|
|
||||||
?assertEqual(ok, filelib:ensure_dir("rotation/rotation.log")),
|
|
||||||
%% fix the permissions on it
|
|
||||||
os:cmd("chown -R u+rwx rotation"),
|
|
||||||
%% delete any old files
|
|
||||||
[ok = file:delete(F) || F <- filelib:wildcard("rotation/*")],
|
|
||||||
%% write a file
|
|
||||||
file:write_file("rotation/rotation.log", "hello"),
|
|
||||||
%% hose up the permissions
|
|
||||||
os:cmd("chown u-w rotation"),
|
|
||||||
?assertMatch({error, _}, rotate_logfile("rotation.log", 10)),
|
|
||||||
?assert(filelib:is_regular("rotation/rotation.log")),
|
|
||||||
os:cmd("chown u+w rotation"),
|
|
||||||
?assertMatch(ok, rotate_logfile("rotation/rotation.log", 10)),
|
|
||||||
?assert(filelib:is_regular("rotation/rotation.log.0")),
|
|
||||||
?assertEqual(false, filelib:is_regular("rotation/rotation.log")),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
check_trace_test() ->
|
|
||||||
lager:start(),
|
|
||||||
trace_filter(none),
|
|
||||||
%% match by module
|
|
||||||
?assertEqual([foo], check_traces([{module, ?MODULE}], ?EMERGENCY, [
|
|
||||||
{[{module, ?MODULE}], config_to_mask(emergency), foo},
|
|
||||||
{[{module, test}], config_to_mask(emergency), bar}], [])),
|
|
||||||
%% match by module, but other unsatisfyable attribute
|
|
||||||
?assertEqual([], check_traces([{module, ?MODULE}], ?EMERGENCY, [
|
|
||||||
{[{module, ?MODULE}, {foo, bar}], config_to_mask(emergency), foo},
|
|
||||||
{[{module, test}], config_to_mask(emergency), bar}], [])),
|
|
||||||
%% match by wildcard module
|
|
||||||
?assertEqual([bar], check_traces([{module, ?MODULE}], ?EMERGENCY, [
|
|
||||||
{[{module, ?MODULE}, {foo, bar}], config_to_mask(emergency), foo},
|
|
||||||
{[{module, '*'}], config_to_mask(emergency), bar}], [])),
|
|
||||||
%% wildcard module, one trace with unsatisfyable attribute
|
|
||||||
?assertEqual([bar], check_traces([{module, ?MODULE}], ?EMERGENCY, [
|
|
||||||
{[{module, '*'}, {foo, bar}], config_to_mask(emergency), foo},
|
|
||||||
{[{module, '*'}], config_to_mask(emergency), bar}], [])),
|
|
||||||
%% wildcard but not present custom trace attribute
|
|
||||||
?assertEqual([bar], check_traces([{module, ?MODULE}], ?EMERGENCY, [
|
|
||||||
{[{module, '*'}, {foo, '*'}], config_to_mask(emergency), foo},
|
|
||||||
{[{module, '*'}], config_to_mask(emergency), bar}], [])),
|
|
||||||
%% wildcarding a custom attribute works when it is present
|
|
||||||
?assertEqual([bar, foo], check_traces([{module, ?MODULE}, {foo, bar}], ?EMERGENCY, [
|
|
||||||
{[{module, '*'}, {foo, '*'}], config_to_mask(emergency), foo},
|
|
||||||
{[{module, '*'}], config_to_mask(emergency), bar}], [])),
|
|
||||||
%% denied by level
|
|
||||||
?assertEqual([], check_traces([{module, ?MODULE}, {foo, bar}], ?INFO, [
|
|
||||||
{[{module, '*'}, {foo, '*'}], config_to_mask(emergency), foo},
|
|
||||||
{[{module, '*'}], config_to_mask(emergency), bar}], [])),
|
|
||||||
%% allowed by level
|
|
||||||
?assertEqual([foo], check_traces([{module, ?MODULE}, {foo, bar}], ?INFO, [
|
|
||||||
{[{module, '*'}, {foo, '*'}], config_to_mask(debug), foo},
|
|
||||||
{[{module, '*'}], config_to_mask(emergency), bar}], [])),
|
|
||||||
?assertEqual([anythingbutnotice, infoandbelow, infoonly], check_traces([{module, ?MODULE}], ?INFO, [
|
|
||||||
{[{module, '*'}], config_to_mask('=debug'), debugonly},
|
|
||||||
{[{module, '*'}], config_to_mask('=info'), infoonly},
|
|
||||||
{[{module, '*'}], config_to_mask('<=info'), infoandbelow},
|
|
||||||
{[{module, '*'}], config_to_mask('!=info'), anythingbutinfo},
|
|
||||||
{[{module, '*'}], config_to_mask('!=notice'), anythingbutnotice}
|
|
||||||
], [])),
|
|
||||||
application:stop(lager),
|
|
||||||
application:stop(goldrush),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
is_loggable_test_() ->
|
|
||||||
[
|
|
||||||
{"Loggable by severity only", ?_assert(is_loggable(lager_msg:new("", alert, [], []),2,me))},
|
|
||||||
{"Not loggable by severity only", ?_assertNot(is_loggable(lager_msg:new("", critical, [], []),1,me))},
|
|
||||||
{"Loggable by severity with destination", ?_assert(is_loggable(lager_msg:new("", alert, [], [you]),2,me))},
|
|
||||||
{"Not loggable by severity with destination", ?_assertNot(is_loggable(lager_msg:new("", critical, [], [you]),1,me))},
|
|
||||||
{"Loggable by destination overriding severity", ?_assert(is_loggable(lager_msg:new("", critical, [], [me]),1,me))}
|
|
||||||
].
|
|
||||||
|
|
||||||
format_time_test_() ->
|
|
||||||
[
|
|
||||||
?_assertEqual("2012-10-04 11:16:23.002",
|
|
||||||
begin
|
|
||||||
{D, T} = format_time({{2012,10,04},{11,16,23,2}}),
|
|
||||||
lists:flatten([D,$ ,T])
|
|
||||||
end),
|
|
||||||
?_assertEqual("2012-10-04 11:16:23.999",
|
|
||||||
begin
|
|
||||||
{D, T} = format_time({{2012,10,04},{11,16,23,999}}),
|
|
||||||
lists:flatten([D,$ ,T])
|
|
||||||
end),
|
|
||||||
?_assertEqual("2012-10-04 11:16:23",
|
|
||||||
begin
|
|
||||||
{D, T} = format_time({{2012,10,04},{11,16,23}}),
|
|
||||||
lists:flatten([D,$ ,T])
|
|
||||||
end),
|
|
||||||
?_assertEqual("2012-10-04 00:16:23.092 UTC",
|
|
||||||
begin
|
|
||||||
{D, T} = format_time({utc, {{2012,10,04},{0,16,23,92}}}),
|
|
||||||
lists:flatten([D,$ ,T])
|
|
||||||
end),
|
|
||||||
?_assertEqual("2012-10-04 11:16:23 UTC",
|
|
||||||
begin
|
|
||||||
{D, T} = format_time({utc, {{2012,10,04},{11,16,23}}}),
|
|
||||||
lists:flatten([D,$ ,T])
|
|
||||||
end)
|
|
||||||
].
|
|
||||||
|
|
||||||
config_to_levels_test() ->
|
|
||||||
?assertEqual([none], config_to_levels('none')),
|
|
||||||
?assertEqual({mask, 0}, config_to_mask('none')),
|
|
||||||
?assertEqual([debug], config_to_levels('=debug')),
|
|
||||||
?assertEqual([debug], config_to_levels('<info')),
|
|
||||||
?assertEqual(levels() -- [debug], config_to_levels('!=debug')),
|
|
||||||
?assertEqual(levels() -- [debug], config_to_levels('>debug')),
|
|
||||||
?assertEqual(levels() -- [debug], config_to_levels('>=info')),
|
|
||||||
?assertEqual(levels() -- [debug], config_to_levels('=>info')),
|
|
||||||
?assertEqual([debug, info, notice], config_to_levels('<=notice')),
|
|
||||||
?assertEqual([debug, info, notice], config_to_levels('=<notice')),
|
|
||||||
?assertEqual([debug], config_to_levels('<info')),
|
|
||||||
?assertEqual([debug], config_to_levels('!info')),
|
|
||||||
?assertError(badarg, config_to_levels(ok)),
|
|
||||||
?assertError(badarg, config_to_levels('<=>info')),
|
|
||||||
?assertError(badarg, config_to_levels('=<=info')),
|
|
||||||
?assertError(badarg, config_to_levels('<==>=<=>info')),
|
|
||||||
%% double negatives DO work, however
|
|
||||||
?assertEqual([debug], config_to_levels('!!=debug')),
|
|
||||||
?assertEqual(levels() -- [debug], config_to_levels('!!!=debug')),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
config_to_mask_test() ->
|
|
||||||
?assertEqual({mask, 0}, config_to_mask('none')),
|
|
||||||
?assertEqual({mask, ?DEBUG bor ?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY}, config_to_mask('debug')),
|
|
||||||
?assertEqual({mask, ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY}, config_to_mask('warning')),
|
|
||||||
?assertEqual({mask, ?DEBUG bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY}, config_to_mask('!=info')),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
mask_to_levels_test() ->
|
|
||||||
?assertEqual([], mask_to_levels(0)),
|
|
||||||
?assertEqual([debug], mask_to_levels(2#10000000)),
|
|
||||||
?assertEqual([debug, info], mask_to_levels(2#11000000)),
|
|
||||||
?assertEqual([debug, info, emergency], mask_to_levels(2#11000001)),
|
|
||||||
?assertEqual([debug, notice, error], mask_to_levels(?DEBUG bor ?NOTICE bor ?ERROR)),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
-endif.
|
|
|
@ -1,2 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/ejabberd_auth_http', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Piotr Nosek <piotr.nosek at erlang-solutions.com>"
|
||||||
|
category: "auth"
|
||||||
|
summary: "Authentication via HTTP request"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,27 +0,0 @@
|
||||||
|
|
||||||
MODULES=`pwd`
|
|
||||||
|
|
||||||
# Put here the path to ejabberd source
|
|
||||||
EJADIR=$MODULES/../git/ejabberd/
|
|
||||||
|
|
||||||
# TODO: Support extraction of multiple modules
|
|
||||||
#MODULE=mod_webpresence
|
|
||||||
MODULE=mod_register_web
|
|
||||||
|
|
||||||
RUNDIR=$MODULES/$MODULE/trunk/
|
|
||||||
PREPARESCRIPT=$EJADIR/contrib/extract_translations/prepare-translation.sh
|
|
||||||
|
|
||||||
# 1. Create the directory $MODULE/msgs/
|
|
||||||
|
|
||||||
# 2. Create the $MODULE.pot
|
|
||||||
#$PREPARESCRIPT -rundir $RUNDIR -ejadir $EJADIR -project $MODULE -src2pot
|
|
||||||
|
|
||||||
# 3. Create a language
|
|
||||||
# cp $MODULE.pot $LANG.$MODULE.po
|
|
||||||
# echo "" > $LANG.$MODULE.msg
|
|
||||||
|
|
||||||
# 3.b Convert msg to po. But it doesn't work! :(
|
|
||||||
#$PREPARESCRIPT -rundir $RUNDIR -ejadir $EJADIR -project $MODULE -srcmsg2po we
|
|
||||||
|
|
||||||
# 4. Update strings
|
|
||||||
$PREPARESCRIPT -rundir $RUNDIR -ejadir $EJADIR -project $MODULE -updateall
|
|
|
@ -1 +0,0 @@
|
||||||
{'src/ejabberd_ircd', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Magnus Henoch <henoch at dtek.chalmers.se>"
|
||||||
|
category: "listener"
|
||||||
|
summary: "IRC server frontend to ejabberd"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,2 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_admin_extra', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# 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"
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Badlop <badlop at process-one.net>"
|
||||||
|
category: "admin"
|
||||||
|
summary: "Additional ejabberd commands"
|
||||||
|
home: "https://github.com/processone/mod_admin_extra"
|
||||||
|
url: "git@github.com:processone/mod_admin_extra.git"
|
|
@ -1,5 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_archive', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_archive_sql', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_archive_odbc', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_archive_webview', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Olivier Goffart <ogoffart at kde.org>"
|
||||||
|
category: "archive"
|
||||||
|
summary: "Supports almost all the XEP-0136 version 0.6 except otr"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,2 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_cron', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
modules:
|
||||||
|
mod_cron: {}
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Badlop <badlop at process-one.net>"
|
||||||
|
category: "admin"
|
||||||
|
summary: "Execute scheduled commands"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,4 +0,0 @@
|
||||||
{'../ejabberd-dev/src/lager_transform', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'../ejabberd-dev/src/lager_util', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/*', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1,14 +0,0 @@
|
||||||
|
|
||||||
# Set the ERL environnement variable if you want to use a specific erl
|
|
||||||
|
|
||||||
ERL ?= $(shell which erl)
|
|
||||||
EJABBERD_DEV ?= ../../ejabberd-dev/trunk
|
|
||||||
|
|
||||||
all:
|
|
||||||
$(ERL) -pa $(EJABBERD_DEV)/ebin -make
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f ebin/*.beam
|
|
||||||
|
|
||||||
dist-clean: clean
|
|
||||||
find . \( -name \*~ -o -name *.swp \) -exec rm -f {} \;
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -1,28 +0,0 @@
|
||||||
% Copy one of this examples into the modules section of your
|
|
||||||
% ejabberd.cfg configuration file and edit it to fit your needs
|
|
||||||
|
|
||||||
|
|
||||||
% log chat messages for all vhosts in current directory in text format
|
|
||||||
{mod_log_chat, []},
|
|
||||||
|
|
||||||
|
|
||||||
% log all vhosts chats in /var/log/ejabberd/chat directory in format
|
|
||||||
{mod_log_chat, [{path, "/var/log/ejabberd/chat"}, {format, html}]},
|
|
||||||
|
|
||||||
|
|
||||||
% log only vh1.myjabberserver.net vhost in /var/log/ejabberd/vh1.myjabberserver.net directory
|
|
||||||
% in HTML format
|
|
||||||
{mod_log_chat, [{host_config,
|
|
||||||
[{"vh1.myjabberserver.net", [{path, "/var/log/ejabberd/vh1.myjabberserver.net"},
|
|
||||||
{format, html}]}]}]},
|
|
||||||
|
|
||||||
|
|
||||||
% log only vh1.myjabberserver.net vhost in /var/log/ejabberd/vh1.myjabberserver.net directory
|
|
||||||
% in HTML format and vh2.myjabberserver.net vhost in /var/log/ejabberd/vh2.myjabberserver.net directory
|
|
||||||
% in text format
|
|
||||||
{mod_log_chat, [{host_config,
|
|
||||||
[{"vh1.myjabberserver.net", [{path, "/var/log/ejabberd/vh1.myjabberserver.net"},
|
|
||||||
{format, html}]},
|
|
||||||
{"vh2.myjabberserver.net", [{path, "/var/log/ejabberd/vh2.myjabberserver.net"},
|
|
||||||
{format, text}]}]}
|
|
||||||
]},
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
; edit this file to fit your needs
|
||||||
|
|
||||||
|
; log all vhosts chats in /var/log/ejabberd/chat directory in html
|
||||||
|
modules:
|
||||||
|
mod_log_chat:
|
||||||
|
path: "/var/log/ejabberd/chat"
|
||||||
|
format: html
|
||||||
|
|
||||||
|
|
||||||
|
; log only vh1.myjabberserver.net vhost in /var/log/ejabberd/vh1.myjabberserver.net directory
|
||||||
|
; in HTML format and vh2.myjabberserver.net vhost in /var/log/ejabberd/vh2.myjabberserver.net directory
|
||||||
|
; in text format
|
||||||
|
; mod_log_chat:
|
||||||
|
; host_config:
|
||||||
|
; - "vh1.myjabberserver.net":
|
||||||
|
; - path: "/var/log/ejabberd/vh1.myjabberserver.net"
|
||||||
|
; - format: html
|
||||||
|
; - "vh2.myjabberserver.net":
|
||||||
|
; - path: "/var/log/ejabberd/vh2.myjabberserver.net"
|
||||||
|
; - format: text
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Jérôme Sautret <jerome.sautret at process-one.net>"
|
||||||
|
category: "log"
|
||||||
|
summary: "Logging chat messages in text files"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,2 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_logsession', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
modules:
|
||||||
|
mod_logsession:
|
||||||
|
sessionlog: "/var/log/ejabberd/session_@HOST@.log"
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Badlop <badlop at process-one.net>"
|
||||||
|
category: "log"
|
||||||
|
summary: "Log session connections to file"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,2 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_logxml', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
modules:
|
||||||
|
mod_logxml:
|
||||||
|
stanza:
|
||||||
|
- iq
|
||||||
|
- other
|
||||||
|
direction:
|
||||||
|
- external
|
||||||
|
orientation:
|
||||||
|
- send
|
||||||
|
- recv
|
||||||
|
logdir: "/tmp/logs/"
|
||||||
|
timezone: universal
|
||||||
|
show_ip: false
|
||||||
|
rotate_days: 1
|
||||||
|
rotate_megs: 100
|
||||||
|
rotate_kpackets: no
|
||||||
|
check_rotate_kpackets: 1
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Badlop <badlop at process-one.net>"
|
||||||
|
category: "log"
|
||||||
|
summary: "Log XMPP packets to XML file"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,4 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"}, {i, "../ejabberd-dev/include"}]}.
|
|
||||||
{'../ejabberd-dev/src/lager_transform', [{outdir, "../ejabberd-dev/ebin"}, {i, "../ejabberd-dev/include"}]}.
|
|
||||||
{'../ejabberd-dev/src/lager_util', [{outdir, "../ejabberd-dev/ebin"}, {i, "../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_mam', [{outdir, "ebin"}, {i, "../ejabberd-dev/include"}, {d, 'LAGER'}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
modules:
|
||||||
|
mod_mam:
|
||||||
|
default_page_size: 25
|
||||||
|
max_page_size: 100
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Holger Weiss <holger at zedat.fu-berlin.de>"
|
||||||
|
category: "archive"
|
||||||
|
summary: "Message Archive Management (XEP-0313)"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,2 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"}, {i, "../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_message_log', [{outdir, "ebin"}, {i, "../ejabberd-dev/include"}]}.
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
modules:
|
||||||
|
mod_message_log:
|
||||||
|
filename: "/var/log/ejabberd/message.log"
|
|
@ -0,0 +1,5 @@
|
||||||
|
author: "Holger Weiss <holger at zedat.fu-berlin.de>"
|
||||||
|
category: "log"
|
||||||
|
summary: "Log one line per message transmission in text file"
|
||||||
|
home: "https://github.com/processone/ejabberd-contrib/tree/master/"
|
||||||
|
url: "git@github.com:processone/ejabberd-contrib.git"
|
|
@ -1,2 +0,0 @@
|
||||||
{'../ejabberd-dev/src/gen_mod', [{outdir, "../ejabberd-dev/ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
||||||
{'src/mod_muc_admin', [{outdir, "ebin"},{i,"../ejabberd-dev/include"}]}.
|
|
|
@ -14,17 +14,6 @@ It also implements Web Admin pages to view the list of existing
|
||||||
rooms.
|
rooms.
|
||||||
|
|
||||||
|
|
||||||
CONFIGURATION
|
|
||||||
=============
|
|
||||||
|
|
||||||
Add the module to your ejabberd.cfg, on the modules section:
|
|
||||||
{modules, [
|
|
||||||
...
|
|
||||||
{mod_muc_admin, []},
|
|
||||||
...
|
|
||||||
]}.
|
|
||||||
|
|
||||||
|
|
||||||
EJABBERD COMMANDS
|
EJABBERD COMMANDS
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
erl -pa ../ejabberd-dev/ebin -pa ebin -make
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
erl -pa ../ejabberd-dev/ebin -pz ebin -make
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
modules:
|
||||||
|
mod_muc_admin: {}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue