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:
|
||||
|
||||
- atom_pubsub: "The atom_pubsub module provides access to all PEP nodes via an
|
||||
AtomPub interface."
|
||||
- atom_pubsub: "Provides access to all PEP nodes via an AtomPub interface."
|
||||
- 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_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:
|
||||
|
||||
- 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
|
||||
required to deploy it.
|
||||
- Run `ejabberdctl install <module>` to get the sources, compile and install
|
||||
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
|
||||
module.
|
||||
|
||||
- Copy generated `.beam` files from the `ebin` directory to the directory
|
||||
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
|
||||
- Edit the configuration file provided in the `conf` dir of the installed
|
||||
module to update to your needs. Then apply the changes to your main ejabberd
|
||||
configuration. On future release, ejabberd will automatically add this file
|
||||
to its runtime configuration without changes.
|
||||
|
||||
- Run `ejabberdctl uninstall <module>` to remove a module from your ejabberd.
|
||||
|
||||
For developers
|
||||
--------------
|
||||
|
||||
The following organization has been set up for the development:
|
||||
|
||||
- Development and compilation of modules should be possible without the
|
||||
ejabberd source code, as the `ejabberd-dev` helper module contains the
|
||||
include files necessary to make compilation possible.
|
||||
- Development and compilation of modules is done by ejabberd. You need
|
||||
Ejabberd installed. Use `ejabberdctl check_module <module>` to ensure
|
||||
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:
|
||||
* `README.txt`: Module description.
|
||||
* `LICENSE.txt`: 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).
|
||||
* `COPYING`: License for the module.
|
||||
* `doc/`: Documentation directory.
|
||||
* `src/`: Source directory.
|
||||
* `src/msgs/`: Directory with translation files (pot, po and msg).
|
||||
* `ebin/`: Empty (target directory for the build).
|
||||
* `conf/`: Directory containing example configuration for your module.
|
||||
* `build.sh`: Unix/Linux build script.
|
||||
* `build.bat`: Windows build script.
|
||||
* `src/`: Erlang source directory.
|
||||
* `lib/`: Elixir source directory.
|
||||
* `priv/msgs/`: Directory with translation files (pot, po and msg).
|
||||
* `conf/<module>.yml`: Configuration for your module.
|
||||
* `<module>.spec`: Yaml description file for your module.
|
||||
|
||||
- Module developers should note in the `README.txt` file whether the
|
||||
module has requirements or known incompatibilities with other modules
|
||||
(for example, by modifying the same main ejabberd modules).
|
||||
module has requirements or known incompatibilities with other 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
|
||||
|
||||
|
||||
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
|
||||
-----
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
CONFIGURATION
|
||||
=============
|
||||
|
||||
Add the module to your ejabberd.cfg, on the modules section:
|
||||
{modules, [
|
||||
...
|
||||
{mod_muc_admin, []},
|
||||
...
|
||||
]}.
|
||||
|
||||
|
||||
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