Compare commits

...

53 Commits

Author SHA1 Message Date
Badlop 3c9ac026ed Create tag for ejabberd 2.1.1.
SVN Revision: 2809
2009-12-17 16:48:35 +00:00
Badlop 402a8c0d35 Prepare 2.1.1 release
SVN Revision: 2808
2009-12-14 14:15:45 +00:00
Badlop d24449488c Print command's reply and newline only when there's something to print.
SVN Revision: 2806
2009-12-11 20:04:36 +00:00
Badlop b9e57a341d Added to ejabberdctl an experimental variable EJABBERD_BYPASS_WARNINGS
SVN Revision: 2804
2009-12-11 19:42:59 +00:00
Badlop 79be929d96 Add support for serving a Unique Room Name (thanks to Pablo Polvorin)(EJAB-1121)
SVN Revision: 2802
2009-12-11 12:30:41 +00:00
Badlop 65aed47873 Show Last Activity menu item in Webadmin only if vhost has mod_last (EJAB-1031)
SVN Revision: 2799
2009-12-09 17:47:02 +00:00
Badlop 8ac16a0ec1 Call in WebAdmin the proper mod_last backend module (EJAB-1031)
SVN Revision: 2798
2009-12-09 17:46:51 +00:00
Badlop 3250c24ff1 This is ejabberd 2.1.x branch, not 2.1.0 tag.
SVN Revision: 2796
2009-12-09 10:09:35 +00:00
Badlop 88b6849e69 Fix erl -setcookie argument in cluster setup (thanks to Jan Koum)
SVN Revision: 2795
2009-12-09 10:09:19 +00:00
Badlop e3b4c99b00 Apply a forgotten part of the original patch (EJAB-1119)
SVN Revision: 2792
2009-12-08 17:32:46 +00:00
Badlop 1f5bf8fbc0 Fix memory and port leak when TLS is enabled in HTTP (thanks to Brian Cully)(EJAB-1119)
SVN Revision: 2790
2009-12-07 17:33:02 +00:00
Badlop f044d6ed28 Fix bug that couldn't connect if starttls_required and zlib were set (EJAB-1118)
SVN Revision: 2789
2009-12-07 15:54:25 +00:00
Christophe Romain 3aa242e2c7 prevent sending duplicated last items if several resources online (EJAB-1116)
SVN Revision: 2786
2009-12-06 23:18:17 +00:00
Badlop 8983cba129 Typo in mod_pubsub_odbc breaks Service Discovery and more (EJAB-1115)
SVN Revision: 2784
2009-12-04 18:35:14 +00:00
Badlop bd97c40f92 Call ejabberd_router:route/3 instead of sending a message (EJAB-1114)
SVN Revision: 2782
2009-12-04 16:31:25 +00:00
Badlop 5a006b977d Small relax the limitation in the mod_pubsub_odbc host option.
SVN Revision: 2781
2009-12-04 16:08:31 +00:00
Badlop 3658da3ae8 Explain limitation in the mod_pubsub_odbc host option.
SVN Revision: 2777
2009-12-03 22:53:56 +00:00
Badlop 2265f52c34 Fix warning of unused variable
SVN Revision: 2776
2009-12-03 22:53:39 +00:00
Badlop 7b244652f1 Use os:getenv to get HOME; if variable is undefined use default values.
SVN Revision: 2773
2009-12-03 15:59:01 +00:00
Badlop 325e67f4cb Use old regexp instead re in 2.x for pre-R12B-4 compatibility.
SVN Revision: 2771
2009-12-02 23:26:28 +00:00
Badlop 6ce660b9c2 IQ sent to resource not connected, return service-unavailable instead of recipient-unavailable (EJAB-1045)
SVN Revision: 2768
2009-12-01 20:00:33 +00:00
Badlop 575e07a986 Forward IQ vCard queries of room occupants to bare JID, not full (EJAB-1045)
SVN Revision: 2767
2009-12-01 20:00:15 +00:00
Badlop 20d1011194 Don't handle internally an IQ vCard if destination is full JID (EJAB-1045)
SVN Revision: 2766
2009-12-01 19:59:59 +00:00
Badlop 3df5277728 Move get_group_name outside the loop (thanks to mikekaganski)
SVN Revision: 2762
2009-11-26 14:46:24 +00:00
Badlop ea4f379bd5 Fix explanation of option content_types. Reorder options.
SVN Revision: 2755
2009-11-23 19:11:37 +00:00
Badlop 51594b6011 Generate main XML file also when exporting only a vhost (EJAB-1098)
SVN Revision: 2753
2009-11-23 18:34:36 +00:00
Badlop 58425ba45d Show informative webpage when browsing the HTTP-Poll page (EJAB-1106)
SVN Revision: 2751
2009-11-23 15:21:05 +00:00
Badlop 7fd3d67ff3 Change captcha.sh to not depend on bash (thanks to Konstantin Khomoutov)(EJAB-1105)
SVN Revision: 2749
2009-11-23 12:43:15 +00:00
Badlop 1716b090f9 Option to define custom HTTP headers in mod_http_fileserver (EJAB-612)
SVN Revision: 2747
2009-11-23 12:00:46 +00:00
Badlop e5e777694d Explain that the example captcha.sh requires Bash because uses RANDOM feature.
SVN Revision: 2745
2009-11-17 15:49:05 +00:00
Badlop 6cf3ae8050 Include IP address, time and module in IBR admin message (thanks to Tsukasa Hamano)
SVN Revision: 2744
2009-11-17 11:14:31 +00:00
Badlop 26c572b7e7 The default value of option ldap_filter is: undefined.
SVN Revision: 2741
2009-11-13 20:16:41 +00:00
Evgeniy Khramtsov 311bf4dbb1 fixes allow_host/2 on subdomains. added hook s2s_allow_host: the hook should return deny or allow
SVN Revision: 2738
2009-11-13 16:19:46 +00:00
Badlop 1511a5dc82 Fix EDoc errors
SVN Revision: 2735
2009-11-06 18:26:06 +00:00
Badlop 041d947e83 Fix bug that forgot listener options when using R12 or older.
SVN Revision: 2734
2009-11-06 18:24:54 +00:00
Christophe Romain 2007b3d496 typo fix that breaks pep
SVN Revision: 2731
2009-11-06 11:01:40 +00:00
Christophe Romain 09e847b97d fix root node deletion match
SVN Revision: 2729
2009-11-05 17:36:15 +00:00
Badlop b9f911554c Fix ProcessOne name in comments.
SVN Revision: 2724
2009-11-04 20:14:22 +00:00
Badlop 24323e8b3b Extend explanation of ldap_encrypt tls (thanks to Konstantin Khomoutov)
SVN Revision: 2723
2009-11-04 20:12:54 +00:00
Badlop 1a5eb4f73d Fix disco on root node, add commands to disco (thanks to Brian Cully)(EJAB-1094)
SVN Revision: 2722
2009-11-04 19:54:15 +00:00
Badlop 3930715712 Send authorization messages outside of get-pending transaction (thanks to Brian Cully)(EJAB-1090)
SVN Revision: 2721
2009-11-04 19:52:33 +00:00
Badlop 64bc97d471 Send authorization messages outside of get-pending transaction (thanks to Brian Cully)(EJAB-1090)
SVN Revision: 2719
2009-11-04 17:38:51 +00:00
Badlop 4aec8dda48 Extend explanation of mod_pubsub "default" rename to "hometree".
SVN Revision: 2718
2009-11-04 09:42:54 +00:00
Badlop 9192c75e1a Fix stringprep Bidi checking (thanks to Alexey Shchepin)(EJAB-1087)
SVN Revision: 2717
2009-11-01 12:15:34 +00:00
Christophe Romain 512d701ef8 minor bugfix, thanks to brian Cully (EJAB-1089)
SVN Revision: 2713
2009-10-27 14:26:22 +00:00
Christophe Romain ef3dd090c7 backport previous patch to pubsub odbc
SVN Revision: 2711
2009-10-27 14:13:18 +00:00
Christophe Romain 3d5fe6a337 fix disco bugs, thanks to Brian Cully (EJAB-1088)
SVN Revision: 2710
2009-10-27 14:07:35 +00:00
Badlop 0906a68c27 Mention in Release Notes the three changes in SQL databases (EJAB-1078)
SVN Revision: 2707
2009-10-23 17:32:12 +00:00
Badlop 798853abb6 Fix mistake that disallowed s2s_out connections when using Erlang R12 or older.
SVN Revision: 2694
2009-10-21 21:11:09 +00:00
Badlop 5e3fdbeeed Mention the change in nodename slash separation in release notes.
SVN Revision: 2689
2009-10-20 15:39:57 +00:00
Badlop 04545f2668 Create branch for ejabberd 2.1.x release line.
SVN Revision: 2688
2009-10-20 15:28:48 +00:00
Christophe Romain f383511e0d add release_notes_2.0.1
SVN Revision: 1338
2008-05-19 22:35:01 +00:00
Jérôme Sautret 2f65188edb Created ejabberd 2.1.X branch.
SVN Revision: 1274
2008-04-03 13:38:34 +00:00
40 changed files with 629 additions and 248 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ release:
@echo "* Do not forget to update the version number in src/ejabberd.app!"
@echo "* Do not forget to update the features in introduction.tex (including \new{} and \improved{} tags)."
@echo "Press any key to continue"
@read foo
##@read foo
@echo "% ejabberd version (automatically generated)." > version.tex
@echo "\newcommand{\version}{"`sed '/vsn/!d;s/\(.*\)"\(.*\)"\(.*\)/\2/' ../src/ejabberd.app`"}" >> version.tex
@echo -n "% Contributed modules (automatically generated)." > contributed_modules.tex
+2 -2
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.0 Developers Guide
<TITLE>Ejabberd 2.1.1 Developers Guide
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -49,7 +49,7 @@ TD P{margin:0px;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic dev.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.0 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.1 Developers Guide</H1><H3 CLASS="titlerest">Alexey Shchepin<BR>
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
+2 -2
View File
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Ejabberd 2.1.0 Feature Sheet
<TITLE>Ejabberd 2.1.1 Feature Sheet
</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
@@ -50,7 +50,7 @@ SPAN{width:20%; float:right; text-align:left; margin-left:auto;}
<!--HEVEA command line is: /usr/bin/hevea -fix -pedantic features.tex -->
<!--CUT DEF section 1 --><P><A NAME="titlepage"></A>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.0 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
</P><TABLE CLASS="title"><TR><TD><H1 CLASS="titlemain">Ejabberd 2.1.1 Feature Sheet</H1><H3 CLASS="titlerest">Sander Devrieze<BR>
<A HREF="mailto:s.devrieze@pandora.be"><TT>mailto:s.devrieze@pandora.be</TT></A><BR>
<A HREF="xmpp:sander@devrieze.dyndns.org"><TT>xmpp:sander@devrieze.dyndns.org</TT></A></H3></TD></TR>
</TABLE><DIV CLASS="center">
+16 -6
View File
@@ -6,7 +6,7 @@
ejabberd 2.1.0
ejabberd 2.1.1
Installation and Operation Guide
@@ -76,7 +76,7 @@ BLOCKQUOTE.figure DIV.center DIV.center HR{display:none;}
<HR SIZE=2><BR>
<BR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.0 </B></FONT></TD></TR>
<TABLE CELLSPACING=6 CELLPADDING=0><TR><TD ALIGN=right NOWRAP> <FONT SIZE=6><B>ejabberd 2.1.1 </B></FONT></TD></TR>
<TR><TD ALIGN=right NOWRAP>&nbsp;</TD></TR>
<TR><TD ALIGN=right NOWRAP> <FONT SIZE=6>Installation and Operation Guide</FONT></TD></TR>
</TABLE><BR>
@@ -1620,7 +1620,8 @@ create accounts, change password or edit vCard that is stored in LDAP.</P><P> <A
LDAP servers. This option is required.
</DD><DT CLASS="dt-description"><B><TT>{ldap_encrypt, none|tls}</TT></B></DT><DD CLASS="dd-description"> Type of connection encryption to the LDAP server.
Allowed values are: <TT>none</TT>, <TT>tls</TT>.
Note that STARTTLS is not supported.
The value <TT>tls</TT> enables encryption by using LDAP over SSL.
Note that STARTTLS encryption is not supported.
The default value is: <TT>none</TT>.
</DD><DT CLASS="dt-description"><B><TT>{ldap_port, Number}</TT></B></DT><DD CLASS="dd-description"> Port to connect to your LDAP server.
The default port is&#XA0;389 if encryption is disabled; and 636 if encryption is enabled.
@@ -1661,7 +1662,7 @@ value is <TT>"%u"</TT>.
</DD></DL>
</DD><DT CLASS="dt-description"><B><TT>{ldap_filter, Filter}</TT></B></DT><DD CLASS="dd-description">
<A HREF="http://tools.ietf.org/html/rfc4515">RFC 4515</A> LDAP filter. The
default is <TT>none</TT>. Example:
default Filter value is: <TT>undefined</TT>. Example:
<TT>"(&amp;(objectClass=shadowAccount)(memberOf=Jabber Users))"</TT>. Please, do
not forget to close brackets and do not use superfluous whitespaces. Also you
<EM>must not</EM> use <TT>ldap_uidattr</TT> attribute in filter because this
@@ -2159,7 +2160,11 @@ Indicate one or more directory index files, similarly to Apache&#X2019;s
DirectoryIndex variable. When a web request hits a directory
instead of a regular file, those directory indices are looked in
order, and the first one found is returned.
Specify a mapping of extensions to content types.
</DD><DT CLASS="dt-description"><B><TT>{custom_headers, [ {Name, Value}, ...]}</TT></B></DT><DD CLASS="dd-description">
Indicate custom HTTP headers to be included in all responses.
Default value is: <TT>[]</TT>
</DD><DT CLASS="dt-description"><B><TT>{content_types, [ {Name, Type}, ...]}</TT></B></DT><DD CLASS="dd-description">
Specify mappings of extension to content type.
There are several content types already defined,
with this option you can add new definitions, modify or delete existing ones.
To delete an existing definition, simply define it with a value: &#X2018;undefined&#X2019;.
@@ -2179,6 +2184,9 @@ To use this module you must enable it:
{docroot, "/var/www"},
{accesslog, "/var/log/ejabberd/access.log"},
{directory_indices, ["index.html", "main.htm"]},
{custom_headers, [{"X-Powered-By", "Erlang/OTP"},
{"X-Fry", "It's a widely-believed fact!"}
]},
{content_types, [{".ogg", "audio/ogg"},
{".png", "image/png"},
{".jpg", undefined}
@@ -2789,6 +2797,8 @@ service. If the <TT>host</TT> option is not specified, the Jabber ID will be the
hostname of the virtual host with the prefix &#X2018;<TT>pubsub.</TT>&#X2019;. The keyword "@HOST@"
is replaced at start time with the real virtual host name.
If you use <TT>mod_pubsub_odbc</TT>, please ensure the prefix contains only one dot,
for example &#X2018;<TT>pubsub.</TT>&#X2019;, or &#X2018;<TT>publish.</TT>&#X2019;,.
</DD><DT CLASS="dt-description"><B><TT>{access_createnode, AccessName}</TT></B></DT><DD CLASS="dd-description">
This option restricts which users are allowed to create pubsub nodes using
ACL and ACCESS.
@@ -3813,7 +3823,7 @@ serving this connection, otherwise a new connection is opened.</P><P> <A NAME="c
and you need to setup another one to make an <TT>ejabberd</TT> cluster. Then do
following steps:</P><OL CLASS="enumerate" type=1><LI CLASS="li-enumerate">
Copy <CODE>~ejabberd/.erlang.cookie</CODE> file from <TT>first</TT> to
<TT>second</TT>.<P>(alt) You can also add &#X2018;<CODE>-cookie content_of_.erlang.cookie</CODE>&#X2019;
<TT>second</TT>.<P>(alt) You can also add &#X2018;<CODE>-setcookie content_of_.erlang.cookie</CODE>&#X2019;
option to all &#X2018;<TT>erl</TT>&#X2019; commands below.</P></LI><LI CLASS="li-enumerate">On <TT>second</TT> run the following command as the <TT>ejabberd</TT> daemon user,
in the working directory of <TT>ejabberd</TT>:<PRE CLASS="verbatim">erl -sname ejabberd \
-mnesia dir "/var/lib/ejabberd/" \
+14 -9
View File
@@ -2163,7 +2163,8 @@ Parameters:
LDAP servers. This option is required.
\titem{\{ldap\_encrypt, none|tls\}} \ind{options!ldap\_encrypt}Type of connection encryption to the LDAP server.
Allowed values are: \term{none}, \term{tls}.
Note that STARTTLS is not supported.
The value \term{tls} enables encryption by using LDAP over SSL.
Note that STARTTLS encryption is not supported.
The default value is: \term{none}.
\titem{\{ldap\_port, Number\}} \ind{options!ldap\_port}Port to connect to your LDAP server.
The default port is~389 if encryption is disabled; and 636 if encryption is enabled.
@@ -2215,7 +2216,7 @@ You can authenticate users against an LDAP directory. Available options are:
\titem{\{ldap\_filter, Filter\}}\ind{options!ldap\_filter}\ind{protocols!RFC 4515:
LDAP String Representation of Search Filters}
\footahref{http://tools.ietf.org/html/rfc4515}{RFC 4515} LDAP filter. The
default is \term{none}. Example:
default Filter value is: \term{undefined}. Example:
\term{"(\&(objectClass=shadowAccount)(memberOf=Jabber Users))"}. Please, do
not forget to close brackets and do not use superfluous whitespaces. Also you
\emph{must not} use \option{ldap\_uidattr} attribute in filter because this
@@ -2853,12 +2854,11 @@ Options:
DirectoryIndex variable. When a web request hits a directory
instead of a regular file, those directory indices are looked in
order, and the first one found is returned.
%B \titem{content\_types} \ind{options!contenttypes}
%M \titem{\{content\_types, \{Extension, Type\} \}} \ind{options!contenttypes}
%B \titem{\{content\_types, [ Extension, Type, ... ]\}} \ind{options!contenttypes}
%B \titem{\{content\_types, [ {Extension, Type}, ... ]\}} \ind{options!contenttypes}
%M \titem{\{content\_types, [ \{Extension, Type\}, ... ]\}} \ind{options!contenttypes}
Specify a mapping of extensions to content types.
\titem{\{custom\_headers, [ \{Name, Value\}, ...]\}} \ind{options!customheaders}
Indicate custom HTTP headers to be included in all responses.
Default value is: \term{[]}
\titem{\{content\_types, [ \{Name, Type\}, ...]\}} \ind{options!contenttypes}
Specify mappings of extension to content type.
There are several content types already defined,
with this option you can add new definitions, modify or delete existing ones.
To delete an existing definition, simply define it with a value: `undefined'.
@@ -2881,6 +2881,9 @@ To use this module you must enable it:
{docroot, "/var/www"},
{accesslog, "/var/log/ejabberd/access.log"},
{directory_indices, ["index.html", "main.htm"]},
{custom_headers, [{"X-Powered-By", "Erlang/OTP"},
{"X-Fry", "It's a widely-believed fact!"}
]},
{content_types, [{".ogg", "audio/ogg"},
{".png", "image/png"},
{".jpg", undefined}
@@ -3570,6 +3573,8 @@ and it requires \modcaps{}.
Options:
\begin{description}
\hostitem{pubsub}
If you use \modpubsubodbc, please ensure the prefix contains only one dot,
for example `\jid{pubsub.}', or `\jid{publish.}',.
\titem{\{access\_createnode, AccessName\}} \ind{options!access\_createnode}
This option restricts which users are allowed to create pubsub nodes using
ACL and ACCESS.
@@ -4914,7 +4919,7 @@ following steps:
\item Copy \verb|~ejabberd/.erlang.cookie| file from \term{first} to
\term{second}.
(alt) You can also add `\verb|-cookie content_of_.erlang.cookie|'
(alt) You can also add `\verb|-setcookie content_of_.erlang.cookie|'
option to all `\shell{erl}' commands below.
\item On \term{second} run the following command as the \ejabberd{} daemon user,
+17 -5
View File
@@ -135,6 +135,8 @@
- Implicit item deletion is not notified when deleting node
- Make PubSub x-data configuration form handles list value
- Make default node name convention XEP-compatible, document usage of hierarchy
- Node names are used verbatim, without separating by slash, unless a
node plugin uses its own separator
- Send authorization update event (XEP-0060, 8.6)
- Support of collection node subscription options
- Support ODBC storage. Experimental, needs more testing.
@@ -207,14 +209,24 @@
Upgrading From ejabberd 2.0.x:
- The database schemas didn't change since ejabberd 1.1.4.
Anyway, it is recommended to backup the Mnesia spool directory and
- The database schemas have three changes since ejabberd 2.0.x.
Check the database creation SQL files and update your database.
1) New table roster_version to support roster versioning.
2) Six new tables for optional pubsub ODBC storage.
3) Some tables in the MySQL database have a new created_at column.
- As usual, it is recommended to backup the Mnesia spool directory and
your SQL database (if used) before upgrading ejabberd.
- The plugin of mod_pubsub "default" is renamed to "flat". You need
to edit the ejabberd configuration file and replace those names.
- Between ejabberd 2.0.0 and 2.0.5, mod_pubsub used "default" as the
default node plugin. But in 2.1.0 this is renamed to "hometree".
You have to edit your ejabberd config file and replace those names.
If you used ejabberd 2.0.5 or older, the database will be updated
automatically. But if you were using ejabberd from SVN, you must
manually run ejabberdctl with the command: rename_default_nodeplugin.
Running this command on already updated database does nothing.
- The listener options 'ip' and inet6' are not documented anymore
- The listener options 'ip' and 'inet6' are not documented anymore
but they are supported and you can continue using them.
There is a new syntax to define IP address and IP version.
As usual, check the ejabberd Guide for more information.
+47
View File
@@ -0,0 +1,47 @@
Release Notes
ejabberd 2.1.1
ejabberd 2.1.1 is the first bugfix release in ejabberd 2.1.x branch.
ejabberd 2.1.1 includes several important bugfixes.
More details of those fixes can be retrieved from:
http://redir.process-one.net/ejabberd-2.1.1
The new code can be downloaded from ejabberd download page:
http://www.process-one.net/en/ejabberd/
The changes are:
* Core
- Call ejabberd_router:route/3 instead of sending a message
- Can't connect if starttls_required and zlib are set
- Routes vCard request to the occupant full JID, but should to bare JID
- S2S: fix allow_host/2 on subdomains. added hook s2s_allow_host
* MUC
- Support converting one-to-one chat to MUC
- Add support for serving a Unique Room Name
* Publish Subscribe
- Receive same last published PEP items at reconnect if several resources online
- Typo in mod_pubsub_odbc breaks Service Discovery and more
* Web
- Fix memory and port leak when TLS is enabled in HTTP
- WebAdmin doesn't report correct last activity with postgresql backend
- Option to define custom HTTP headers in mod_http_fileserver
- Show informative webpage when browsing the HTTP-Poll page
* Other
- Change captcha.sh to not depend on bash
- Generate main XML file also when exporting only a vhost
- Fix last newline in ejabberdctl result
- Guide: fix -setcookie, mod_pubsub_odbc host, content_types
Bug reports
You can officially report bugs on ProcessOne support site:
http://support.process-one.net/
+1 -1
View File
@@ -1,2 +1,2 @@
% ejabberd version (automatically generated).
\newcommand{\version}{2.1.0}
\newcommand{\version}{2.1.1}
+1 -1
View File
@@ -2,7 +2,7 @@
{application, ejabberd,
[{description, "ejabberd"},
{vsn, "2.1.0"},
{vsn, "2.1.1"},
{modules, [acl,
adhoc,
configure,
+1 -2
View File
@@ -187,7 +187,6 @@ init([{SockMod, Socket}, Opts]) ->
(_) -> false
end, Opts),
TLSOpts = [verify_none | TLSOpts1],
Zlib = lists:member(zlib, Opts) andalso (not StartTLSRequired),
IP = peerip(SockMod, Socket),
%% Check if IP is blacklisted:
case is_ip_blacklisted(IP) of
@@ -1220,7 +1219,7 @@ handle_info({route, From, To, Packet}, StateName, StateData) ->
"iq" ->
IQ = jlib:iq_query_info(Packet),
case IQ of
#iq{xmlns = ?NS_VCARD} ->
#iq{xmlns = ?NS_VCARD} when (To#jid.luser == "") or (To#jid.lresource == "") ->
Host = StateData#state.server,
case ets:lookup(sm_iqtable, {?NS_VCARD, Host}) of
[{_, Module, Function, Opts}] ->
+6 -2
View File
@@ -197,8 +197,12 @@ process(["help" | Mode]) ->
process(Args) ->
AccessCommands = get_accesscommands(),
{String, Code} = process2(Args, AccessCommands),
io:format(String),
io:format("\n"),
case String of
[] -> ok;
_ ->
io:format(String),
io:format("\n")
end,
Code.
%% @spec (Args::[string()], AccessCommands) -> {String::string(), Code::integer()}
+1 -1
View File
@@ -129,7 +129,7 @@ init_udp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
init_tcp(PortIP, Module, Opts, SockOpts, Port, IPS) ->
SockOpts2 = case erlang:system_info(otp_release) >= "R13B" of
true -> [{send_timeout_close, true} | SockOpts];
false -> []
false -> SockOpts
end,
Res = gen_tcp:listen(Port, [binary,
{packet, 0},
+14 -9
View File
@@ -212,7 +212,7 @@ add_user(El, Domain, User, Password) ->
El),
ok;
{atomic, exists} ->
?INFO_MSG("User ~p@~p already exists, using stored profile...~n",
io:format("Account ~s@~s already exists, updating it...~n",
[User, Domain]),
io:format(""),
ok = exmpp_xml:foreach(
@@ -417,10 +417,10 @@ to_list(B) when is_atom(B) -> atom_to_list(B).
%%%==================================
%%%% Export server
%%%% Export hosts
%% @spec (Dir::string()) -> ok
export_server(Dir) ->
%% @spec (Dir::string(), Hosts::[string()]) -> ok
export_hosts(Dir, Hosts) ->
try_start_exmpp(),
FnT = make_filename_template(),
@@ -430,7 +430,6 @@ export_server(Dir) ->
print(Fd, make_piefxis_xml_head()),
print(Fd, make_piefxis_server_head()),
Hosts = ?MYHOSTS,
FilesAndHosts = [{make_host_filename(FnT, Host), Host} || Host <- Hosts],
[print(Fd, make_xinclude(FnH)) || {FnH, _Host} <- FilesAndHosts],
@@ -442,15 +441,21 @@ export_server(Dir) ->
ok.
%%%==================================
%%%% Export server
%% @spec (Dir::string()) -> ok
export_server(Dir) ->
Hosts = ?MYHOSTS,
export_hosts(Dir, Hosts).
%%%==================================
%%%% Export host
%% @spec (Dir::string(), Host::string()) -> ok
export_host(Dir, Host) ->
try_start_exmpp(),
FnT = make_filename_template(),
FnH = make_host_filename(FnT, Host),
export_host(Dir, FnH, Host).
Hosts = [Host],
export_hosts(Dir, Hosts).
%% @spec (Dir::string(), Fn::string(), Host::string()) -> ok
export_host(Dir, FnH, Host) ->
+25 -9
View File
@@ -486,15 +486,31 @@ update_tables() ->
%% Check if host is in blacklist or white list
allow_host(MyServer, S2SHost) ->
case ejabberd_config:get_local_option({{s2s_host, S2SHost},MyServer}) of
deny -> false;
allow -> true;
_ ->
case ejabberd_config:get_local_option({s2s_default_policy, MyServer}) of
deny -> false;
allow -> true;
_ -> true %% The default s2s policy is allow
end
case lists:filter(
fun(Host) ->
is_subdomain(MyServer, Host)
end, ?MYHOSTS) of
[MyHost|_] ->
allow_host1(MyHost, S2SHost);
[] ->
allow_host1(MyServer, S2SHost)
end.
allow_host1(MyHost, S2SHost) ->
case ejabberd_config:get_local_option({{s2s_host, S2SHost}, MyHost}) of
deny -> false;
allow -> true;
_ ->
case ejabberd_config:get_local_option({s2s_default_policy, MyHost}) of
deny -> false;
_ ->
case ejabberd_hooks:run_fold(s2s_allow_host, MyHost,
allow, [MyHost, S2SHost]) of
deny -> false;
allow -> true;
_ -> true
end
end
end.
%% Get information about S2S connections of the specified type.
-1
View File
@@ -272,7 +272,6 @@ open_socket2(Type, Addr, Port) ->
case (catch ejabberd_socket:connect(Addr, Port,
[binary, {packet, 0},
{send_timeout, ?TCP_SEND_TIMEOUT},
{send_timeout_close, true},
{active, false}, Type | SockOpts],
Timeout)) of
{ok, _Socket} = R -> R;
+1 -1
View File
@@ -481,7 +481,7 @@ do_route(From, To, Packet) ->
_ ->
Err =
jlib:make_error_reply(
Packet, ?ERR_RECIPIENT_UNAVAILABLE),
Packet, ?ERR_SERVICE_UNAVAILABLE),
ejabberd_router:route(To, From, Err)
end;
_ ->
+10 -2
View File
@@ -159,8 +159,12 @@ debug ()
echo " control+c, control+c"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
echo "Press any key to continue"
read foo
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
read foo
fi
echo ""
$EXEC_CMD "$ERL \
$NAME debug-${ERLANG_NODE} \
@@ -184,8 +188,12 @@ live ()
echo " q(). and press the Enter key"
echo ""
echo "--------------------------------------------------------------------"
echo "To bypass permanently this warning, add to ejabberdctl.cfg the line:"
echo " EJABBERD_BYPASS_WARNINGS=true"
echo "Press any key to continue"
read foo
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
read foo
fi
echo ""
$EXEC_CMD "$ERL \
$NAME $ERLANG_NODE \
+1
View File
@@ -47,6 +47,7 @@
-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_OWNER, "http://jabber.org/protocol/pubsub#owner").
+1 -1
View File
@@ -22,7 +22,7 @@
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%%% 02111-1307 USA
%%%
%%% 2009, improvements from Process-One to support correct PEP handling
%%% 2009, improvements from ProcessOne to support correct PEP handling
%%% through s2s, use less memory, and speedup global caps handling
%%%----------------------------------------------------------------------
+1 -1
View File
@@ -175,7 +175,7 @@ store_last_info(User, Server, TimeStamp, Status) ->
mnesia:transaction(F).
%% @spec (LUser::string(), LServer::string()) ->
%% {ok, Timestamp::integer(), Status::string()} | not_found
%% {ok, TimeStamp::integer(), Status::string()} | not_found
get_last_info(LUser, LServer) ->
case catch mnesia:dirty_read(last_activity, {LUser, LServer}) of
{'EXIT', _Reason} ->
+22
View File
@@ -413,6 +413,17 @@ do_route1(Host, ServerHost, Access, HistorySize, RoomShaper,
ejabberd_router:route(To,
From,
jlib:iq_to_xml(Res));
#iq{type = get,
xmlns = ?NS_MUC_UNIQUE
} = IQ ->
Res = IQ#iq{type = result,
sub_el =
[{xmlelement, "unique",
[{"xmlns", ?NS_MUC_UNIQUE}],
[iq_get_unique(From)]}]},
ejabberd_router:route(To,
From,
jlib:iq_to_xml(Res));
#iq{} ->
Err = jlib:make_error_reply(
Packet,
@@ -570,6 +581,7 @@ iq_disco_info(Lang) ->
{xmlelement, "feature", [{"var", ?NS_DISCO_INFO}], []},
{xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
{xmlelement, "feature", [{"var", ?NS_MUC}], []},
{xmlelement, "feature", [{"var", ?NS_MUC_UNIQUE}], []},
{xmlelement, "feature", [{"var", ?NS_REGISTER}], []},
{xmlelement, "feature", [{"var", ?NS_RSM}], []},
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}].
@@ -669,6 +681,16 @@ flush() ->
{"var", Var}],
[{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
%% @doc Get a pseudo unique Room Name. The Room Name is generated as a hash of
%% the requester JID, the local time and a random salt.
%%
%% "pseudo" because we don't verify that there is not a room
%% with the returned Name already created, nor mark the generated Name
%% as "already used". But in practice, it is unique enough. See
%% http://xmpp.org/extensions/xep-0045.html#createroom-unique
iq_get_unique(From) ->
{xmlcdata, sha:sha(term_to_binary([From, now(), randoms:get_string()]))}.
iq_get_register_info(Host, From, Lang) ->
{LUser, LServer, _} = jlib:jid_tolower(From),
LUS = {LUser, LServer},
+52 -6
View File
@@ -470,9 +470,10 @@ normal_state({route, From, ToNick,
{xmlelement, "iq", Attrs, _Els} = Packet},
StateData) ->
Lang = xml:get_attr_s("xml:lang", Attrs),
StanzaId = xml:get_attr_s("id", Attrs),
case {(StateData#state.config)#config.allow_query_users,
is_user_online(From, StateData)} of
{true, true} ->
is_user_online_iq(StanzaId, From, StateData)} of
{true, {true, NewId, FromFull}} ->
case find_jid_by_nick(ToNick, StateData) of
false ->
case jlib:iq_query_info(Packet) of
@@ -489,13 +490,15 @@ normal_state({route, From, ToNick,
end;
ToJID ->
{ok, #user{nick = FromNick}} =
?DICT:find(jlib:jid_tolower(From),
?DICT:find(jlib:jid_tolower(FromFull),
StateData#state.users),
{ToJID2, Packet2} = handle_iq_vcard(FromFull, ToJID,
StanzaId, NewId,Packet),
ejabberd_router:route(
jlib:jid_replace_resource(StateData#state.jid, FromNick),
ToJID, Packet)
ToJID2, Packet2)
end;
{_, false} ->
{_, {false, _, _}} ->
case jlib:iq_query_info(Packet) of
reply ->
ok;
@@ -829,7 +832,6 @@ process_groupchat_message(From, {xmlelement, "message", Attrs, _Els} = Packet,
{next_state, normal_state, StateData}
end.
%% @doc Check if this non participant can send message to room.
%%
%% XEP-0045 v1.23:
@@ -969,6 +971,50 @@ is_user_online(JID, StateData) ->
LJID = jlib:jid_tolower(JID),
?DICT:is_key(LJID, StateData#state.users).
%%%
%%% Handle IQ queries of vCard
%%%
is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource /= "" ->
{is_user_online(JID, StateData), StanzaId, JID};
is_user_online_iq(StanzaId, JID, StateData) when JID#jid.lresource == "" ->
try stanzaid_unpack(StanzaId) of
{OriginalId, Resource} ->
JIDWithResource = jlib:jid_replace_resource(JID, Resource),
{is_user_online(JIDWithResource, StateData),
OriginalId, JIDWithResource}
catch
_:_ ->
{is_user_online(JID, StateData), StanzaId, JID}
end.
handle_iq_vcard(FromFull, ToJID, StanzaId, NewId, Packet) ->
ToBareJID = jlib:jid_remove_resource(ToJID),
IQ = jlib:iq_query_info(Packet),
handle_iq_vcard2(FromFull, ToJID, ToBareJID, StanzaId, NewId, IQ, Packet).
handle_iq_vcard2(_FromFull, ToJID, ToBareJID, StanzaId, _NewId,
#iq{type = get, xmlns = ?NS_VCARD}, Packet)
when ToBareJID /= ToJID ->
{ToBareJID, change_stanzaid(StanzaId, ToJID, Packet)};
handle_iq_vcard2(_FromFull, ToJID, _ToBareJID, _StanzaId, NewId, _IQ, Packet) ->
{ToJID, change_stanzaid(NewId, Packet)}.
stanzaid_pack(OriginalId, Resource) ->
"berd"++base64:encode_to_string("ejab\0" ++ OriginalId ++ "\0" ++ Resource).
stanzaid_unpack("berd"++StanzaIdBase64) ->
StanzaId = base64:decode_to_string(StanzaIdBase64),
["ejab", OriginalId, Resource] = string:tokens(StanzaId, "\0"),
{OriginalId, Resource}.
change_stanzaid(NewId, Packet) ->
{xmlelement, Name, Attrs, Els} = jlib:remove_attr("id", Packet),
{xmlelement, Name, [{"id", NewId} | Attrs], Els}.
change_stanzaid(PreviousId, ToJID, Packet) ->
NewId = stanzaid_pack(PreviousId, ToJID#jid.lresource),
change_stanzaid(NewId, Packet).
%%%
%%%
role_to_list(Role) ->
case Role of
moderator -> "moderator";
+71 -28
View File
@@ -191,8 +191,8 @@ init([ServerHost, Opts]) ->
ets:insert(gen_mod:get_module_proc(Host, config), {max_items_node, MaxItemsNode}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {last_item_cache, Plugins}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {max_items_node, LastItemCache}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {last_item_cache, LastItemCache}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {max_items_node, MaxItemsNode}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}),
ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
@@ -631,7 +631,7 @@ disco_local_features(Acc, _From, To, [], _Lang) ->
end,
{result, Feats ++ lists:map(fun(Feature) ->
?NS_PUBSUB++"#"++Feature
end, features(Host, []))};
end, features(Host, <<>>))};
disco_local_features(Acc, _From, _To, _Node, _Lang) ->
Acc.
@@ -718,10 +718,16 @@ disco_sm_items(Acc, From, To, SNode, _Lang) ->
presence_probe(#jid{luser = User, lserver = Server, lresource = Resource} = JID, JID, Pid) ->
Proc = gen_mod:get_module_proc(Server, ?PROCNAME),
%%?DEBUG("presence probe self ~s@~s/~s ~s@~s/~s",[User,Server,Resource,element(2,JID),element(3,JID),element(4,JID)]),
gen_server:cast(Proc, {presence, JID, Pid}),
gen_server:cast(Proc, {presence, User, Server, [Resource], JID});
presence_probe(#jid{luser = User, lserver = Server}, #jid{luser = User, lserver = Server}, _Pid) ->
%% ignore presence_probe from other ressources for the current user
%% this way, we do not send duplicated last items if user already connected with other clients
ok;
presence_probe(#jid{luser = User, lserver = Server, lresource = Resource}, #jid{lserver = Host} = JID, _Pid) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
%%?DEBUG("presence probe peer ~s@~s/~s ~s@~s/~s",[User,Server,Resource,element(2,JID),element(3,JID),element(4,JID)]),
gen_server:cast(Proc, {presence, User, Server, [Resource], JID}).
%% -------
@@ -1030,6 +1036,18 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) ->
end
end.
command_disco_info(_Host, <<?NS_COMMANDS>>, _From) ->
IdentityEl = {xmlelement, "identity", [{"category", "automation"},
{"type", "command-list"}],
[]},
{result, [IdentityEl]};
command_disco_info(_Host, <<?NS_PUBSUB_GET_PENDING>>, _From) ->
IdentityEl = {xmlelement, "identity", [{"category", "automation"},
{"type", "command-node"}],
[]},
FeaturesEl = {xmlelement, "feature", [{"var", ?NS_COMMANDS}], []},
{result, [IdentityEl, FeaturesEl]}.
node_disco_info(Host, Node, From) ->
node_disco_info(Host, Node, From, true, true).
node_disco_identity(Host, Node, From) ->
@@ -1092,21 +1110,38 @@ iq_disco_info(Host, SNode, From, Lang) ->
{xmlelement, "feature", [{"var", ?NS_DISCO_INFO}], []},
{xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
{xmlelement, "feature", [{"var", ?NS_COMMANDS}], []},
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
lists:map(fun(Feature) ->
{xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++Feature}], []}
end, features(Host, Node))};
<<?NS_COMMANDS>> ->
command_disco_info(Host, Node, From);
<<?NS_PUBSUB_GET_PENDING>> ->
command_disco_info(Host, Node, From);
_ ->
node_disco_info(Host, Node, From)
end.
iq_disco_items(Host, [], From) ->
{result, lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) ->
{result, Path} = node_call(Type, node_to_path, [SubNode]),
[Name|_] = lists:reverse(Path),
{xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []}
end, tree_action(Host, get_subnodes, [Host, <<>>, From]))};
case tree_action(Host, get_subnodes, [Host, <<>>, From]) of
Nodes when is_list(Nodes) ->
{result, lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) ->
{result, Path} = node_call(Type, node_to_path, [SubNode]),
[Name|_] = lists:reverse(Path),
{xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []}
end, Nodes)};
Other ->
Other
end;
iq_disco_items(Host, ?NS_COMMANDS, _From) ->
%% TODO: support localization of this string
CommandItems = [{xmlelement, "item", [{"jid", Host}, {"node", ?NS_PUBSUB_GET_PENDING}, {"name", "Get Pending"}], []}],
{result, CommandItems};
iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From) ->
CommandItems = [],
{result, CommandItems};
iq_disco_items(Host, Item, From) ->
case string:tokens(Item, "!") of
[_SNode, _ItemID] ->
@@ -1122,7 +1157,9 @@ iq_disco_items(Host, Item, From) ->
end,
Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}}) ->
{xmlelement, "item", [{"jid", Host}|nodeAttr(SubNode)], []}
{result, Path} = node_call(Type, node_to_path, [SubNode]),
[Name|_] = lists:reverse(Path),
{xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []}
end, tree_call(Host, get_subnodes, [Host, Node, From])),
Items = lists:map(
fun(#pubsub_item{itemid = {RN, _}}) ->
@@ -1174,7 +1211,7 @@ iq_get_vcard(Lang) ->
[{xmlcdata,
translate:translate(Lang,
"ejabberd Publish-Subscribe module") ++
"\nCopyright (c) 2004-2009 Process-One"}]}].
"\nCopyright (c) 2004-2009 ProcessOne"}]}].
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) ->
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)).
@@ -1366,6 +1403,13 @@ adhoc_request(Host, _ServerHost, Owner,
Error ->
Error
end;
adhoc_request(_Host, _ServerHost, _Owner, #adhoc_request{action = "cancel"},
_Access, _Plugins) ->
#adhoc_response{status = canceled};
adhoc_request(Host, ServerHost, Owner, #adhoc_request{action = []} = R,
Access, Plugins) ->
adhoc_request(Host, ServerHost, Owner, R#adhoc_request{action = "execute"},
Access, Plugins);
adhoc_request(_Host, _ServerHost, _Owner, Other, _Access, _Plugins) ->
?DEBUG("Couldn't process ad hoc command:~n~p", [Other]),
{error, ?ERR_ITEM_NOT_FOUND}.
@@ -1417,17 +1461,12 @@ send_pending_auth_events(Host, Node, Owner) ->
?DEBUG("Sending pending auth events for ~s on ~s:~s",
[jlib:jid_to_string(Owner), Host, node_to_string(Node)]),
Action =
fun (#pubsub_node{id = NodeID, type = Type} = N) ->
fun (#pubsub_node{id = NodeID, type = Type}) ->
case lists:member("get-pending", features(Type)) of
true ->
case node_call(Type, get_affiliation, [NodeID, Owner]) of
{result, owner} ->
{result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]),
lists:foreach(fun({J, pending, _SubID}) -> send_authorization_request(N, jlib:make_jid(J));
({J, pending}) -> send_authorization_request(N, jlib:make_jid(J));
(_) -> ok
end, Subscriptions),
{result, ok};
node_call(Type, get_node_subscriptions, [NodeID]);
_ ->
{error, ?ERR_FORBIDDEN}
end;
@@ -1436,7 +1475,11 @@ send_pending_auth_events(Host, Node, Owner) ->
end
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, _} ->
{result, {N, Subscriptions}} ->
lists:foreach(fun({J, pending, _SubID}) -> send_authorization_request(N, jlib:make_jid(J));
({J, pending}) -> send_authorization_request(N, jlib:make_jid(J));
(_) -> ok
end, Subscriptions),
#adhoc_response{};
Err ->
Err
@@ -1472,7 +1515,7 @@ send_authorization_request(#pubsub_node{owners = Owners, nodeid = {Host, Node}},
{"label", translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?")}],
[{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]},
lists:foreach(fun(Owner) ->
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza}
ejabberd_router:route(service_jid(Host), jlib:make_jid(Owner), Stanza)
end, Owners).
find_authorization_response(Packet) ->
@@ -1522,7 +1565,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) ->
[{xmlelement, "subscription",
[{"jid", jlib:jid_to_string(JID)}|nodeAttr(SNode)] ++ SubAttrs,
[]}]),
ejabberd_router ! {route, service_jid(Host), JID, Stanza}.
ejabberd_router:route(service_jid(Host), JID, Stanza).
handle_authorization_response(Host, From, To, Packet, XFields) ->
case {lists:keysearch("pubsub#node", 1, XFields),
@@ -1768,7 +1811,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
%%<li>The node is the root collection node, which cannot be deleted.</li>
%%<li>The specified node does not exist.</li>
%%</ul>
delete_node(_Host, [], _Owner) ->
delete_node(_Host, <<>>, _Owner) ->
%% Node is the root
{error, ?ERR_NOT_ALLOWED};
delete_node(Host, Node, Owner) ->
@@ -2293,7 +2336,7 @@ send_items(Host, Node, NodeId, Type, LJID, last) ->
Stanza = event_stanza_with_delay(
[{xmlelement, "items", nodeAttr(Node),
itemsEls([LastItem])}], ModifNow, ModifLjid),
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}
ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza)
end;
send_items(Host, Node, NodeId, Type, LJID, Number) ->
ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of
@@ -2318,7 +2361,7 @@ send_items(Host, Node, NodeId, Type, LJID, Number) ->
[{xmlelement, "items", nodeAttr(Node),
itemsEls(ToSend)}])
end,
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}.
ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza).
%% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response}
%% Host = host()
@@ -2720,7 +2763,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) ->
[{"jid", jlib:jid_to_string(JID)},
%{"subid", SubId},
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
end,
Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) ->
case lists:member(Owner, Owners) of
@@ -3068,7 +3111,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp
end,
SHIMStanza = add_headers(Stanza, collection_shim(Node, Nodes)),
lists:foreach(fun(To) ->
ejabberd_router ! {route, From, jlib:make_jid(To), SHIMStanza}
ejabberd_router:route(From, jlib:make_jid(To), SHIMStanza)
end, LJIDs)
end, NodesByJID),
%% Handles implicit presence subscriptions
@@ -3102,7 +3145,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp
end
end, [], user_resources(U, S)),
lists:foreach(fun(To) ->
ejabberd_router ! {route, Sender, jlib:make_jid(To), Stanza}
ejabberd_router:route(Sender, jlib:make_jid(To), Stanza)
end, LJIDs)
end)
end, Contacts);
@@ -3583,7 +3626,7 @@ features(Type) ->
{'EXIT', {undef, _}} -> [];
Result -> Result
end.
features(Host, []) ->
features(Host, <<>>) ->
lists:usort(lists:foldl(fun(Plugin, Acc) ->
Acc ++ features(Plugin)
end, [], plugins(Host)));
+72 -29
View File
@@ -191,8 +191,8 @@ init([ServerHost, Opts]) ->
ets:insert(gen_mod:get_module_proc(Host, config), {max_items_node, MaxItemsNode}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {nodetree, NodeTree}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {plugins, Plugins}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {last_item_cache, Plugins}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {max_items_node, LastItemCache}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {last_item_cache, LastItemCache}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {max_items_node, MaxItemsNode}),
ets:insert(gen_mod:get_module_proc(ServerHost, config), {pep_mapping, PepMapping}),
ejabberd_hooks:add(disco_sm_identity, ServerHost, ?MODULE, disco_sm_identity, 75),
ejabberd_hooks:add(disco_sm_features, ServerHost, ?MODULE, disco_sm_features, 75),
@@ -434,7 +434,7 @@ disco_local_features(Acc, _From, To, [], _Lang) ->
end,
{result, Feats ++ lists:map(fun(Feature) ->
?NS_PUBSUB++"#"++Feature
end, features(Host, []))};
end, features(Host, <<>>))};
disco_local_features(Acc, _From, _To, _Node, _Lang) ->
Acc.
@@ -521,10 +521,16 @@ disco_sm_items(Acc, From, To, SNode, _Lang) ->
presence_probe(#jid{luser = User, lserver = Server, lresource = Resource} = JID, JID, Pid) ->
Proc = gen_mod:get_module_proc(Server, ?PROCNAME),
%%?DEBUG("presence probe self ~s@~s/~s ~s@~s/~s",[User,Server,Resource,element(2,JID),element(3,JID),element(4,JID)]),
gen_server:cast(Proc, {presence, JID, Pid}),
gen_server:cast(Proc, {presence, User, Server, [Resource], JID});
presence_probe(#jid{luser = User, lserver = Server}, #jid{luser = User, lserver = Server}, _Pid) ->
%% ignore presence_probe from other ressources for the current user
%% this way, we do not send duplicated last items if user already connected with other clients
ok;
presence_probe(#jid{luser = User, lserver = Server, lresource = Resource}, #jid{lserver = Host} = JID, _Pid) ->
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
%%?DEBUG("presence probe peer ~s@~s/~s ~s@~s/~s",[User,Server,Resource,element(2,JID),element(3,JID),element(4,JID)]),
gen_server:cast(Proc, {presence, User, Server, [Resource], JID}).
%% -------
@@ -834,6 +840,18 @@ do_route(ServerHost, Access, Plugins, Host, From, To, Packet) ->
end
end.
command_disco_info(_Host, <<?NS_COMMANDS>>, _From) ->
IdentityEl = {xmlelement, "identity", [{"category", "automation"},
{"type", "command-list"}],
[]},
{result, [IdentityEl]};
command_disco_info(_Host, <<?NS_PUBSUB_GET_PENDING>>, _From) ->
IdentityEl = {xmlelement, "identity", [{"category", "automation"},
{"type", "command-node"}],
[]},
FeaturesEl = {xmlelement, "feature", [{"var", ?NS_COMMANDS}], []},
{result, [IdentityEl, FeaturesEl]}.
node_disco_info(Host, Node, From) ->
node_disco_info(Host, Node, From, true, true).
node_disco_identity(Host, Node, From) ->
@@ -897,22 +915,39 @@ iq_disco_info(Host, SNode, From, Lang) ->
{xmlelement, "feature", [{"var", ?NS_DISCO_INFO}], []},
{xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
{xmlelement, "feature", [{"var", ?NS_COMMANDS}], []},
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
lists:map(fun
("rsm")-> {xmlelement, "feature", [{"var", ?NS_RSM}], []};
(T) -> {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++T}], []}
end, features(Host, Node))};
<<?NS_COMMANDS>> ->
command_disco_info(Host, Node, From);
<<?NS_PUBSUB_GET_PENDING>> ->
command_disco_info(Host, Node, From);
_ ->
node_disco_info(Host, Node, From)
end.
iq_disco_items(Host, [], From, _RSM) ->
{result, lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) ->
{result, Path} = node_call(Type, node_to_path, [SubNode]),
[Name|_] = lists:reverse(Path),
{xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []}
end, tree_action(Host, get_subnodes, [Host, <<>>, From]))};
case tree_action(Host, get_subnodes, [Host, <<>>, From]) of
Nodes when is_list(Nodes) ->
{result, lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) ->
{result, Path} = node_call(Type, node_to_path, [SubNode]),
[Name|_] = lists:reverse(Path),
{xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []}
end, Nodes)};
Other ->
Other
end;
iq_disco_items(Host, ?NS_COMMANDS, _From, _RSM) ->
%% TODO: support localization of this string
CommandItems = [{xmlelement, "item", [{"jid", Host}, {"node", ?NS_PUBSUB_GET_PENDING}, {"name", "Get Pending"}], []}],
{result, CommandItems};
iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From, _RSM) ->
CommandItems = [],
{result, CommandItems};
iq_disco_items(Host, Item, From, RSM) ->
case string:tokens(Item, "!") of
[_SNode, _ItemID] ->
@@ -928,7 +963,9 @@ iq_disco_items(Host, Item, From, RSM) ->
end,
Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}}) ->
{xmlelement, "item", [{"jid", Host}|nodeAttr(SubNode)], []}
{result, Path} = node_call(Type, node_to_path, [SubNode]),
[Name|_] = lists:reverse(Path),
{xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []}
end, tree_call(Host, get_subnodes, [Host, Node, From])),
Items = lists:map(
fun(#pubsub_item{itemid = {RN, _}}) ->
@@ -980,7 +1017,7 @@ iq_get_vcard(Lang) ->
[{xmlcdata,
translate:translate(Lang,
"ejabberd Publish-Subscribe module") ++
"\nCopyright (c) 2004-2009 Process-One"}]}].
"\nCopyright (c) 2004-2009 ProcessOne"}]}].
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang) ->
iq_pubsub(Host, ServerHost, From, IQType, SubEl, Lang, all, plugins(ServerHost)).
@@ -1175,6 +1212,13 @@ adhoc_request(Host, _ServerHost, Owner,
Error ->
Error
end;
adhoc_request(_Host, _ServerHost, _Owner, #adhoc_request{action = "cancel"},
_Access, _Plugins) ->
#adhoc_response{status = canceled};
adhoc_request(Host, ServerHost, Owner, #adhoc_request{action = []} = R,
Access, Plugins) ->
adhoc_request(Host, ServerHost, Owner, R#adhoc_request{action = "execute"},
Access, Plugins);
adhoc_request(_Host, _ServerHost, _Owner, Other, _Access, _Plugins) ->
?DEBUG("Couldn't process ad hoc command:~n~p", [Other]),
{error, ?ERR_ITEM_NOT_FOUND}.
@@ -1227,17 +1271,12 @@ send_pending_auth_events(Host, Node, Owner) ->
?DEBUG("Sending pending auth events for ~s on ~s:~s",
[jlib:jid_to_string(Owner), Host, node_to_string(Node)]),
Action =
fun (#pubsub_node{id = NodeID, type = Type} = N) ->
fun (#pubsub_node{id = NodeID, type = Type}) ->
case lists:member("get-pending", features(Type)) of
true ->
case node_call(Type, get_affiliation, [NodeID, Owner]) of
{result, owner} ->
{result, Subscriptions} = node_call(Type, get_node_subscriptions, [NodeID]),
lists:foreach(fun({J, pending, _SubID}) -> send_authorization_request(N, jlib:make_jid(J));
({J, pending}) -> send_authorization_request(N, jlib:make_jid(J));
(_) -> ok
end, Subscriptions),
{result, ok};
node_call(Type, get_node_subscriptions, [NodeID]);
_ ->
{error, ?ERR_FORBIDDEN}
end;
@@ -1246,7 +1285,11 @@ send_pending_auth_events(Host, Node, Owner) ->
end
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, _} ->
{result, {N, Subscriptions}} ->
lists:foreach(fun({J, pending, _SubID}) -> send_authorization_request(N, jlib:make_jid(J));
({J, pending}) -> send_authorization_request(N, jlib:make_jid(J));
(_) -> ok
end, Subscriptions),
#adhoc_response{};
Err ->
Err
@@ -1282,7 +1325,7 @@ send_authorization_request(#pubsub_node{nodeid = {Host, Node}, type = Type, id =
{"label", translate:translate(Lang, "Allow this Jabber ID to subscribe to this pubsub node?")}],
[{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]},
lists:foreach(fun(Owner) ->
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza}
ejabberd_router:route(service_jid(Host), jlib:make_jid(Owner), Stanza)
end, node_owners(Host, Type, NodeId)).
find_authorization_response(Packet) ->
@@ -1332,7 +1375,7 @@ send_authorization_approval(Host, JID, SNode, Subscription) ->
[{xmlelement, "subscription",
[{"jid", jlib:jid_to_string(JID)}|nodeAttr(SNode)] ++ SubAttrs,
[]}]),
ejabberd_router ! {route, service_jid(Host), JID, Stanza}.
ejabberd_router:route(service_jid(Host), JID, Stanza).
handle_authorization_response(Host, From, To, Packet, XFields) ->
case {lists:keysearch("pubsub#node", 1, XFields),
@@ -1578,7 +1621,7 @@ create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
%%<li>The node is the root collection node, which cannot be deleted.</li>
%%<li>The specified node does not exist.</li>
%%</ul>
delete_node(_Host, [], _Owner) ->
delete_node(_Host, <<>>, _Owner) ->
%% Node is the root
{error, ?ERR_NOT_ALLOWED};
delete_node(Host, Node, Owner) ->
@@ -2120,7 +2163,7 @@ send_items(Host, Node, NodeId, Type, LJID, last) ->
[{xmlelement, "items", nodeAttr(Node),
itemsEls([LastItem])}], ModifNow, ModifLjid)
end,
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza};
ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza);
send_items(Host, Node, NodeId, Type, LJID, Number) ->
ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of
{result, []} ->
@@ -2144,7 +2187,7 @@ send_items(Host, Node, NodeId, Type, LJID, Number) ->
[{xmlelement, "items", nodeAttr(Node),
itemsEls(ToSend)}])
end,
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}.
ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza).
%% @spec (Host, JID, Plugins) -> {error, Reason} | {result, Response}
%% Host = host()
@@ -2529,7 +2572,7 @@ set_subscriptions(Host, Node, From, EntitiesEls) ->
[{"jid", jlib:jid_to_string(JID)},
%{"subid", SubId},
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
end,
Action = fun(#pubsub_node{type = Type, id = NodeId}) ->
case lists:member(Owner, node_owners_call(Type, NodeId)) of
@@ -2877,7 +2920,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp
end,
SHIMStanza = add_headers(Stanza, collection_shim(Node, Nodes)),
lists:foreach(fun(To) ->
ejabberd_router ! {route, From, jlib:make_jid(To), SHIMStanza}
ejabberd_router:route(From, jlib:make_jid(To), SHIMStanza)
end, LJIDs)
end, NodesByJID),
%% Handles implicit presence subscriptions
@@ -2911,7 +2954,7 @@ broadcast_stanza(Host, Node, _NodeId, _Type, NodeOptions, SubsByDepth, NotifyTyp
end
end, [], user_resources(U, S)),
lists:foreach(fun(To) ->
ejabberd_router ! {route, Sender, jlib:make_jid(To), Stanza}
ejabberd_router:route(Sender, jlib:make_jid(To), Stanza)
end, LJIDs)
end)
end, Contacts);
@@ -3416,7 +3459,7 @@ features(Type) ->
{'EXIT', {undef, _}} -> [];
Result -> Result
end.
features(Host, []) ->
features(Host, <<>>) ->
lists:usort(lists:foldl(fun(Plugin, Acc) ->
Acc ++ features(Plugin)
end, [], plugins(Host)));
@@ -3520,7 +3563,7 @@ transaction_retry(Host, Fun, Trans, Count) ->
odbc_conn({_U, Host, _R})->
Host;
odbc_conn(Host) ->
Host--"pubsub.". %% TODO, improve that for custom host
lists:dropwhile(fun(A) -> A/=$. end, Host) -- ".".
%% escape value for database storage
escape({_U, _H, _R}=JID)->
+12 -6
View File
@@ -154,17 +154,21 @@ get_parentnodes_tree(Host, NodeID, _From) ->
get_subnodes(Host, NodeID, _From) ->
get_subnodes(Host, NodeID).
get_subnodes(Host, <<>>) ->
get_subnodes_helper(Host, <<>>);
get_subnodes(Host, NodeID) ->
case find_node(Host, NodeID) of
false -> {error, ?ERR_ITEM_NOT_FOUND};
_ ->
Q = qlc:q([Node || #pubsub_node{nodeid = {NHost, _},
parents = Parents} = Node <- mnesia:table(pubsub_node),
Host == NHost,
lists:member(NodeID, Parents)]),
qlc:e(Q)
_ -> get_subnodes_helper(Host, NodeID)
end.
get_subnodes_helper(Host, NodeID) ->
Q = qlc:q([Node || #pubsub_node{nodeid = {NHost, _},
parents = Parents} = Node <- mnesia:table(pubsub_node),
Host == NHost,
lists:member(NodeID, Parents)]),
qlc:e(Q).
get_subnodes_tree(Host, NodeID, From) ->
Pred = fun (NID, #pubsub_node{parents = Parents}) ->
lists:member(NID, Parents)
@@ -224,6 +228,8 @@ validate_parentage(_Key, _Owners, []) ->
true;
validate_parentage(Key, Owners, [[] | T]) ->
validate_parentage(Key, Owners, T);
validate_parentage(Key, Owners, [<<>> | T]) ->
validate_parentage(Key, Owners, T);
validate_parentage(Key, Owners, [ParentID | T]) ->
case find_node(Key, ParentID) of
false -> {error, ?ERR_ITEM_NOT_FOUND};
+1 -1
View File
@@ -197,7 +197,7 @@ get_subnodes_tree(Host, Node) ->
end, [], pubsub_node)
end.
%% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason}
%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok | {error, Reason}
%% Host = mod_pubsub:host() | mod_pubsub:jid()
%% Node = mod_pubsub:pubsubNode()
%% NodeType = mod_pubsub:nodeType()
+1 -1
View File
@@ -203,7 +203,7 @@ get_subnodes_tree(Host, Node) ->
[]
end.
%% @spec (Host, Node, Type, Owner, Options) -> ok | {error, Reason}
%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok | {error, Reason}
%% Host = mod_pubsub:host() | mod_pubsub:jid()
%% Node = mod_pubsub:pubsubNode()
%% NodeType = mod_pubsub:nodeType()
+1 -1
View File
@@ -148,7 +148,7 @@ get_subnodes_tree(Host, Node, _From) ->
get_subnodes_tree(_Host, _Node) ->
[].
%% @spec (Host, Node, Type, Owner, Options) -> ok
%% @spec (Host, Node, Type, Owner, Options, Parents) -> ok
%% Host = mod_pubsub:host()
%% Node = mod_pubsub:pubsubNode()
%% Type = mod_pubsub:nodeType()
+61 -49
View File
@@ -1,5 +1,5 @@
--- mod_pubsub.erl 2009-10-20 16:33:47.000000000 +0200
+++ mod_pubsub_odbc.erl 2009-10-20 16:33:26.000000000 +0200
--- mod_pubsub.erl 2009-12-07 00:17:20.000000000 +0100
+++ mod_pubsub_odbc.erl 2009-12-07 00:17:59.000000000 +0100
@@ -42,7 +42,7 @@
%%% 6.2.3.1, 6.2.3.5, and 6.3. For information on subscription leases see
%%% XEP-0060 section 12.18.
@@ -284,7 +284,7 @@
true ->
% resource not concerned about that subscription
ok
@@ -825,10 +628,10 @@
@@ -831,10 +634,10 @@
{result, Subscriptions} = node_action(Host, PType, get_entity_subscriptions, [Host, Subscriber]),
lists:foreach(fun
({Node, subscribed, _, JID}) ->
@@ -297,7 +297,7 @@
true ->
node_action(Host, Type, unsubscribe_node, [NodeId, Subscriber, JID, all]);
false ->
@@ -943,7 +746,8 @@
@@ -949,7 +752,8 @@
sub_el = SubEl} = IQ ->
{xmlelement, _, QAttrs, _} = SubEl,
Node = xml:get_attr_s("node", QAttrs),
@@ -307,7 +307,7 @@
{result, IQRes} ->
jlib:iq_to_xml(
IQ#iq{type = result,
@@ -1048,7 +852,7 @@
@@ -1066,7 +870,7 @@
[] ->
["leaf"]; %% No sub-nodes: it's a leaf node
_ ->
@@ -316,7 +316,7 @@
{result, []} -> ["collection"];
{result, _} -> ["leaf", "collection"];
_ -> []
@@ -1064,8 +868,9 @@
@@ -1082,8 +886,9 @@
[];
true ->
[{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []} |
@@ -328,9 +328,9 @@
end, features(Type))]
end,
%% TODO: add meta-data info (spec section 5.4)
@@ -1093,21 +898,22 @@
{xmlelement, "feature", [{"var", ?NS_DISCO_ITEMS}], []},
@@ -1112,8 +917,9 @@
{xmlelement, "feature", [{"var", ?NS_PUBSUB}], []},
{xmlelement, "feature", [{"var", ?NS_COMMANDS}], []},
{xmlelement, "feature", [{"var", ?NS_VCARD}], []}] ++
- lists:map(fun(Feature) ->
- {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++Feature}], []}
@@ -338,24 +338,36 @@
+ ("rsm")-> {xmlelement, "feature", [{"var", ?NS_RSM}], []};
+ (T) -> {xmlelement, "feature", [{"var", ?NS_PUBSUB++"#"++T}], []}
end, features(Host, Node))};
_ ->
<<?NS_COMMANDS>> ->
command_disco_info(Host, Node, From);
@@ -1123,7 +929,7 @@
node_disco_info(Host, Node, From)
end.
-iq_disco_items(Host, [], From) ->
+iq_disco_items(Host, [], From, _RSM) ->
{result, lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}, type = Type}) ->
{result, Path} = node_call(Type, node_to_path, [SubNode]),
[Name|_] = lists:reverse(Path),
{xmlelement, "item", [{"jid", Host}, {"name", Name}|nodeAttr(SubNode)], []}
end, tree_action(Host, get_subnodes, [Host, <<>>, From]))};
case tree_action(Host, get_subnodes, [Host, <<>>, From]) of
Nodes when is_list(Nodes) ->
{result, lists:map(
@@ -1135,14 +941,14 @@
Other ->
Other
end;
-iq_disco_items(Host, ?NS_COMMANDS, _From) ->
+iq_disco_items(Host, ?NS_COMMANDS, _From, _RSM) ->
%% TODO: support localization of this string
CommandItems = [{xmlelement, "item", [{"jid", Host}, {"node", ?NS_PUBSUB_GET_PENDING}, {"name", "Get Pending"}], []}],
{result, CommandItems};
-iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From) ->
+iq_disco_items(_Host, ?NS_PUBSUB_GET_PENDING, _From, _RSM) ->
CommandItems = [],
{result, CommandItems};
-iq_disco_items(Host, Item, From) ->
+iq_disco_items(Host, Item, From, RSM) ->
case string:tokens(Item, "!") of
[_SNode, _ItemID] ->
{result, []};
@@ -1115,10 +921,10 @@
@@ -1150,10 +956,10 @@
Node = string_to_node(SNode),
Action =
fun(#pubsub_node{type = Type, id = NodeId}) ->
@@ -369,7 +381,7 @@
end,
Nodes = lists:map(
fun(#pubsub_node{nodeid = {_, SubNode}}) ->
@@ -1129,7 +935,7 @@
@@ -1166,7 +972,7 @@
{result, Name} = node_call(Type, get_item_name, [Host, Node, RN]),
{xmlelement, "item", [{"jid", Host}, {"name", Name}], []}
end, NodeItems),
@@ -378,7 +390,7 @@
end,
case transaction(Host, Node, Action, sync_dirty) of
{result, {_, Result}} -> {result, Result};
@@ -1258,7 +1064,8 @@
@@ -1295,7 +1101,8 @@
(_, Acc) ->
Acc
end, [], xml:remove_cdata(Els)),
@@ -388,7 +400,7 @@
{get, "subscriptions"} ->
get_subscriptions(Host, Node, From, Plugins);
{get, "affiliations"} ->
@@ -1281,7 +1088,9 @@
@@ -1318,7 +1125,9 @@
iq_pubsub_owner(Host, ServerHost, From, IQType, SubEl, Lang) ->
{xmlelement, _, _, SubEls} = SubEl,
@@ -399,7 +411,7 @@
case Action of
[{xmlelement, Name, Attrs, Els}] ->
Node = string_to_node(xml:get_attr_s("node", Attrs)),
@@ -1404,7 +1213,8 @@
@@ -1448,7 +1257,8 @@
_ -> []
end
end,
@@ -409,7 +421,7 @@
sync_dirty) of
{result, Res} -> Res;
Err -> Err
@@ -1444,7 +1254,7 @@
@@ -1487,7 +1297,7 @@
%%% authorization handling
@@ -418,16 +430,16 @@
Lang = "en", %% TODO fix
Stanza = {xmlelement, "message",
[],
@@ -1473,7 +1283,7 @@
@@ -1516,7 +1326,7 @@
[{xmlelement, "value", [], [{xmlcdata, "false"}]}]}]}]},
lists:foreach(fun(Owner) ->
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(Owner), Stanza}
ejabberd_router:route(service_jid(Host), jlib:make_jid(Owner), Stanza)
- end, Owners).
+ end, node_owners(Host, Type, NodeId)).
find_authorization_response(Packet) ->
{xmlelement, _Name, _Attrs, Els} = Packet,
@@ -1537,8 +1347,8 @@
@@ -1580,8 +1390,8 @@
"true" -> true;
_ -> false
end,
@@ -438,7 +450,7 @@
{result, Subscriptions} = node_call(Type, get_subscriptions, [NodeId, Subscriber]),
if
not IsApprover ->
@@ -1729,7 +1539,7 @@
@@ -1772,7 +1582,7 @@
Reply = [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "create", nodeAttr(Node),
[]}]}],
@@ -447,7 +459,7 @@
{result, {Result, broadcast}} ->
%%Lang = "en", %% TODO: fix
%%OwnerKey = jlib:jid_tolower(jlib:jid_remove_resource(Owner)),
@@ -1837,7 +1647,7 @@
@@ -1880,7 +1690,7 @@
%%<li>The node does not exist.</li>
%%</ul>
subscribe_node(Host, Node, From, JID, Configuration) ->
@@ -456,7 +468,7 @@
{result, GoodSubOpts} -> GoodSubOpts;
_ -> invalid
end,
@@ -1845,7 +1655,7 @@
@@ -1888,7 +1698,7 @@
error -> {"", "", ""};
J -> jlib:jid_tolower(J)
end,
@@ -465,7 +477,7 @@
Features = features(Type),
SubscribeFeature = lists:member("subscribe", Features),
OptionsFeature = lists:member("subscription-options", Features),
@@ -1864,9 +1674,13 @@
@@ -1907,9 +1717,13 @@
{"", "", ""} ->
{false, false};
_ ->
@@ -482,7 +494,7 @@
end
end,
if
@@ -2197,7 +2011,7 @@
@@ -2240,7 +2054,7 @@
%% <p>The permission are not checked in this function.</p>
%% @todo We probably need to check that the user doing the query has the right
%% to read the items.
@@ -491,7 +503,7 @@
MaxItems =
if
SMaxItems == "" -> get_max_items_node(Host);
@@ -2236,11 +2050,11 @@
@@ -2279,11 +2093,11 @@
node_call(Type, get_items,
[NodeId, From,
AccessModel, PresenceSubscription, RosterGroup,
@@ -505,7 +517,7 @@
SendItems = case ItemIDs of
[] ->
Items;
@@ -2253,7 +2067,8 @@
@@ -2296,7 +2110,8 @@
%% number of items sent to MaxItems:
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB}],
[{xmlelement, "items", nodeAttr(Node),
@@ -515,7 +527,7 @@
Error ->
Error
end
@@ -2285,16 +2100,27 @@
@@ -2328,16 +2143,27 @@
%% @doc <p>Resend the items of a node to the user.</p>
%% @todo use cache-last-item feature
send_items(Host, Node, NodeId, Type, LJID, last) ->
@@ -541,15 +553,15 @@
+ event_stanza_with_delay(
[{xmlelement, "items", nodeAttr(Node),
- itemsEls([LastItem])}], ModifNow, ModifLjid),
- ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza}
- ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza)
- end;
+ itemsEls([LastItem])}], ModifNow, ModifLjid)
+ end,
+ ejabberd_router ! {route, service_jid(Host), jlib:make_jid(LJID), Stanza};
+ ejabberd_router:route(service_jid(Host), jlib:make_jid(LJID), Stanza);
send_items(Host, Node, NodeId, Type, LJID, Number) ->
ToSend = case node_action(Host, Type, get_items, [NodeId, LJID]) of
{result, []} ->
@@ -2420,29 +2246,12 @@
@@ -2463,29 +2289,12 @@
error ->
{error, ?ERR_BAD_REQUEST};
_ ->
@@ -582,7 +594,7 @@
end, Entities),
{result, []};
_ ->
@@ -2495,11 +2304,11 @@
@@ -2538,11 +2347,11 @@
end.
read_sub(Subscriber, Node, NodeID, SubID, Lang) ->
@@ -596,7 +608,7 @@
OptionsEl = {xmlelement, "options", [{"jid", jlib:jid_to_string(Subscriber)},
{"subid", SubID}|nodeAttr(Node)],
[XdataEl]},
@@ -2525,7 +2334,7 @@
@@ -2568,7 +2377,7 @@
end.
set_options_helper(Configuration, JID, NodeID, SubID, Type) ->
@@ -605,7 +617,7 @@
{result, GoodSubOpts} -> GoodSubOpts;
_ -> invalid
end,
@@ -2554,7 +2363,7 @@
@@ -2597,7 +2406,7 @@
write_sub(_Subscriber, _NodeID, _SubID, invalid) ->
{error, extended_error(?ERR_BAD_REQUEST, "invalid-options")};
write_sub(Subscriber, NodeID, SubID, Options) ->
@@ -614,9 +626,9 @@
{error, notfound} ->
{error, extended_error(?ERR_NOT_ACCEPTABLE, "invalid-subid")};
{result, _} ->
@@ -2722,8 +2531,8 @@
@@ -2765,8 +2574,8 @@
{"subscription", subscription_to_string(Sub)} | nodeAttr(Node)], []}]}]},
ejabberd_router ! {route, service_jid(Host), jlib:make_jid(JID), Stanza}
ejabberd_router:route(service_jid(Host), jlib:make_jid(JID), Stanza)
end,
- Action = fun(#pubsub_node{owners = Owners, type = Type, id = NodeId}) ->
- case lists:member(Owner, Owners) of
@@ -625,7 +637,7 @@
true ->
Result = lists:foldl(fun({JID, Subscription, SubId}, Acc) ->
@@ -3007,7 +2816,7 @@
@@ -3050,7 +2859,7 @@
{Depth, [{N, get_node_subs(N)} || N <- Nodes]}
end, tree_call(Host, get_parentnodes_tree, [Host, Node, service_jid(Host)]))}
end,
@@ -634,7 +646,7 @@
{result, CollSubs} -> CollSubs;
_ -> []
end.
@@ -3021,9 +2830,9 @@
@@ -3064,9 +2873,9 @@
get_options_for_subs(NodeID, Subs) ->
lists:foldl(fun({JID, subscribed, SubID}, Acc) ->
@@ -646,7 +658,7 @@
_ -> Acc
end;
(_, Acc) ->
@@ -3221,6 +3030,30 @@
@@ -3264,6 +3073,30 @@
Result
end.
@@ -677,7 +689,7 @@
%% @spec (Host, Options) -> MaxItems
%% Host = host()
%% Options = [Option]
@@ -3607,7 +3440,13 @@
@@ -3650,7 +3483,13 @@
tree_action(Host, Function, Args) ->
?DEBUG("tree_action ~p ~p ~p",[Host,Function,Args]),
Fun = fun() -> tree_call(Host, Function, Args) end,
@@ -692,7 +704,7 @@
%% @doc <p>node plugin call.</p>
node_call(Type, Function, Args) ->
@@ -3627,13 +3466,13 @@
@@ -3670,13 +3509,13 @@
node_action(Host, Type, Function, Args) ->
?DEBUG("node_action ~p ~p ~p ~p",[Host,Type,Function,Args]),
@@ -708,7 +720,7 @@
case tree_call(Host, get_node, [Host, Node]) of
N when is_record(N, pubsub_node) ->
case Action(N) of
@@ -3646,8 +3485,14 @@
@@ -3689,8 +3528,14 @@
end
end, Trans).
@@ -725,7 +737,7 @@
{result, Result} -> {result, Result};
{error, Error} -> {error, Error};
{atomic, {result, Result}} -> {result, Result};
@@ -3655,6 +3500,15 @@
@@ -3698,6 +3543,15 @@
{aborted, Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{aborted, Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR};
@@ -741,14 +753,14 @@
{'EXIT', Reason} ->
?ERROR_MSG("transaction return internal error: ~p~n", [{'EXIT', Reason}]),
{error, ?ERR_INTERNAL_SERVER_ERROR};
@@ -3663,6 +3517,17 @@
@@ -3706,6 +3560,17 @@
{error, ?ERR_INTERNAL_SERVER_ERROR}
end.
+odbc_conn({_U, Host, _R})->
+ Host;
+odbc_conn(Host) ->
+ Host--"pubsub.". %% TODO, improve that for custom host
+ lists:dropwhile(fun(A) -> A/=$. end, Host) -- ".".
+
+%% escape value for database storage
+escape({_U, _H, _R}=JID)->
+16 -4
View File
@@ -33,6 +33,7 @@
stop/1,
stream_feature_register/1,
unauthenticated_iq_register/4,
try_register/5,
process_iq/3]).
-include("ejabberd.hrl").
@@ -224,7 +225,7 @@ try_register(User, Server, Password, Source, Lang) ->
case ejabberd_auth:try_register(User, Server, Password) of
{atomic, ok} ->
send_welcome_message(JID),
send_registration_notifications(JID),
send_registration_notifications(JID, Source),
ok;
Error ->
remove_timeout(Source),
@@ -264,15 +265,17 @@ send_welcome_message(JID) ->
ok
end.
send_registration_notifications(UJID) ->
send_registration_notifications(UJID, Source) ->
Host = UJID#jid.lserver,
case gen_mod:get_module_opt(Host, ?MODULE, registration_watchers, []) of
[] -> ok;
JIDs when is_list(JIDs) ->
Body = lists:flatten(
io_lib:format(
"The user '~s' was just created on node ~w.",
[jlib:jid_to_string(UJID), node()])),
"[~s] The account ~s was registered from IP address ~s "
"on node ~w using ~p.",
[get_time_string(), jlib:jid_to_string(UJID),
ip_to_string(Source), node(), ?MODULE])),
lists:foreach(
fun(S) ->
case jlib:string_to_jid(S) of
@@ -380,3 +383,12 @@ remove_timeout(Source) ->
ok
end.
ip_to_string(Source) when is_tuple(Source) -> inet_parse:ntoa(Source);
ip_to_string(undefined) -> "undefined";
ip_to_string(_) -> "unknown".
get_time_string() -> write_time(erlang:localtime()).
%% Function copied from ejabberd_logger_h.erl and customized
write_time({{Y,Mo,D},{H,Mi,S}}) ->
io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w",
[Y, Mo, D, H, Mi, S]).
+2 -1
View File
@@ -124,11 +124,12 @@ get_user_roster(Items, US) ->
SRUsers =
lists:foldl(
fun(Group, Acc1) ->
GroupName = get_group_name(S, Group),
lists:foldl(
fun(User, Acc2) ->
if User == US -> Acc2;
true -> dict:append(User,
get_group_name(S, Group),
GroupName,
Acc2)
end
end, Acc1, get_group_users(S, Group))
+1 -1
View File
@@ -310,7 +310,7 @@ do_route(ServerHost, From, To, Packet) ->
if
(User /= "") or (Resource /= "") ->
Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE),
ejabberd_router ! {route, To, From, Err};
ejabberd_router:route(To, From, Err);
true ->
IQ = jlib:iq_query_info(Packet),
case IQ of
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* ejabberd, Copyright (C) 2002-2009 Process-one
* ejabberd, Copyright (C) 2002-2009 ProcessOne
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
+1 -1
View File
@@ -369,7 +369,7 @@ static int stringprep_erl_control(ErlDrvData drv_data,
}
last_ral = info & D1Mask;
have_ral = have_ral || last_ral;
have_l = info & D2Mask;
have_l |= info & D2Mask;
ADD_UCHAR(ruc);
}
+11 -6
View File
@@ -35,6 +35,9 @@
receive_headers/1,
url_encode/1]).
%% Callbacks
-export([init/2]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("ejabberd_http.hrl").
@@ -79,7 +82,10 @@
start(SockData, Opts) ->
supervisor:start_child(ejabberd_http_sup, [SockData, Opts]).
start_link({SockMod, Socket}, Opts) ->
start_link(SockData, Opts) ->
{ok, proc_lib:spawn_link(ejabberd_http, init, [SockData, Opts])}.
init({SockMod, Socket}, Opts) ->
TLSEnabled = lists:member(tls, Opts),
TLSOpts = lists:filter(fun({certfile, _}) -> true;
(_) -> false
@@ -129,11 +135,10 @@ start_link({SockMod, Socket}, Opts) ->
?DEBUG("S: ~p~n", [RequestHandlers]),
?INFO_MSG("started: ~p", [{SockMod1, Socket1}]),
{ok, proc_lib:spawn_link(ejabberd_http,
receive_headers,
[#state{sockmod = SockMod1,
socket = Socket1,
request_handlers = RequestHandlers}])}.
State = #state{sockmod = SockMod1,
socket = Socket1,
request_handlers = RequestHandlers},
receive_headers(State).
become_controller(_Pid) ->
+21 -1
View File
@@ -154,12 +154,32 @@ process([], #request{data = Data,
end
end;
_ ->
{200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], ""}
HumanHTMLxmlel = get_human_html_xmlel(),
{200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], HumanHTMLxmlel}
end;
process(_, _Request) ->
{400, [], {xmlelement, "h1", [],
[{xmlcdata, "400 Bad Request"}]}}.
%% Code copied from mod_http_bind.erl and customized
get_human_html_xmlel() ->
Heading = "ejabberd " ++ atom_to_list(?MODULE),
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
[{xmlelement, "head", [],
[{xmlelement, "title", [], [{xmlcdata, Heading}]}]},
{xmlelement, "body", [],
[{xmlelement, "h1", [], [{xmlcdata, Heading}]},
{xmlelement, "p", [],
[{xmlcdata, "An implementation of "},
{xmlelement, "a",
[{"href", "http://xmpp.org/extensions/xep-0025.html"}],
[{xmlcdata, "Jabber HTTP Polling (XEP-0025)"}]}]},
{xmlelement, "p", [],
[{xmlcdata, "This web page is only informative. "
"To use HTTP-Poll you need a Jabber/XMPP client that supports it."}
]}
]}]}.
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
%%%----------------------------------------------------------------------
+29 -11
View File
@@ -1467,7 +1467,7 @@ list_users(Host, Query, Lang, URLFunc) ->
FUsers =
case length(SUsers) of
N when N =< 100 ->
[list_given_users(SUsers, "../", Lang, URLFunc)];
[list_given_users(Host, SUsers, "../", Lang, URLFunc)];
N ->
NParts = trunc(math:sqrt(N * 0.618)) + 1,
M = trunc(N / NParts) + 1,
@@ -1542,9 +1542,10 @@ list_users_in_diapason(Host, Diap, Lang, URLFunc) ->
N1 = list_to_integer(S1),
N2 = list_to_integer(S2),
Sub = lists:sublist(SUsers, N1, N2 - N1 + 1),
[list_given_users(Sub, "../../", Lang, URLFunc)].
[list_given_users(Host, Sub, "../../", Lang, URLFunc)].
list_given_users(Users, Prefix, Lang, URLFunc) ->
list_given_users(Host, Users, Prefix, Lang, URLFunc) ->
ModLast = get_lastactivity_module(Host),
?XE("table",
[?XE("thead",
[?XE("tr",
@@ -1562,11 +1563,10 @@ list_given_users(Users, Prefix, Lang, URLFunc) ->
FLast =
case ejabberd_sm:get_user_resources(User, Server) of
[] ->
case mnesia:dirty_read({last_activity, US}) of
[] ->
case ModLast:get_last_info(User, Server) of
not_found ->
?T("Never");
[E] ->
Shift = element(3, E),
{ok, Shift, _Status} ->
TimeStamp = {Shift div 1000000,
Shift rem 1000000,
0},
@@ -1591,6 +1591,18 @@ list_given_users(Users, Prefix, Lang, URLFunc) ->
end, Users)
)]).
get_lastactivity_module(Server) ->
case lists:member(mod_last, gen_mod:loaded_modules(Server)) of
true -> mod_last;
_ -> mod_last_odbc
end.
get_lastactivity_menuitem_list(Server) ->
case get_lastactivity_module(Server) of
mod_last -> [{"last-activity", "Last Activity"}];
mod_last_odbc -> []
end.
us_to_list({User, Server}) ->
jlib:jid_to_string({User, Server, ""}).
@@ -1947,7 +1959,13 @@ get_node(global, Node, ["db"], Query, Lang) ->
end;
get_node(global, Node, ["backup"], Query, Lang) ->
HomeDir = re:replace(filename:nativename(os:cmd("echo $HOME")), "\n", "", [{return, list}]),
HomeDirRaw = case {os:getenv("HOME"), os:type()} of
{EnvHome, _} when is_list(EnvHome) -> EnvHome;
{false, win32} -> "C:/";
{false, {win32, _Osname}} -> "C:/";
{false, _} -> "/tmp/"
end,
HomeDir = filename:nativename(HomeDirRaw),
ResS = case node_backup_parse_query(Node, Query) of
nothing -> [];
ok -> [?XREST("Submitted")];
@@ -2694,9 +2712,9 @@ make_host_menu(Host, HostNodeMenu, Lang, JID) ->
HostFixed = [{"acls", "Access Control Lists"},
{"access", "Access Rules"},
{"users", "Users"},
{"online-users", "Online Users"},
{"last-activity", "Last Activity"},
{"nodes", "Nodes", HostNodeMenu},
{"online-users", "Online Users"}]
++ get_lastactivity_menuitem_list(Host) ++
[{"nodes", "Nodes", HostNodeMenu},
{"stats", "Statistics"}]
++ get_menu_items_hook({host, Host}, Lang),
HostBasePath = url_to_path(HostBase),
+16 -9
View File
@@ -69,7 +69,14 @@ process([], #request{method = 'POST',
ejabberd_http_bind:process_request(Data, IP);
process([], #request{method = 'GET',
data = []}) ->
Heading = "Ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION,
get_human_html_xmlel();
process(_Path, _Request) ->
?DEBUG("Bad Request: ~p", [_Request]),
{400, [], {xmlelement, "h1", [],
[{xmlcdata, "400 Bad Request"}]}}.
get_human_html_xmlel() ->
Heading = "ejabberd " ++ atom_to_list(?MODULE) ++ " v" ++ ?MOD_HTTP_BIND_VERSION,
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"}],
[{xmlelement, "head", [],
[{xmlelement, "title", [], [{xmlcdata, Heading}]}]},
@@ -77,14 +84,14 @@ process([], #request{method = 'GET',
[{xmlelement, "h1", [], [{xmlcdata, Heading}]},
{xmlelement, "p", [],
[{xmlcdata, "An implementation of "},
{xmlelement, "a", [{"href", "http://www.xmpp.org/extensions/xep-0206.html"}],
[{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]}
]}]};
process(_Path, _Request) ->
?DEBUG("Bad Request: ~p", [_Request]),
{400, [], {xmlelement, "h1", [],
[{xmlcdata, "400 Bad Request"}]}}.
{xmlelement, "a",
[{"href", "http://xmpp.org/extensions/xep-0206.html"}],
[{xmlcdata, "XMPP over BOSH (XEP-0206)"}]}]},
{xmlelement, "p", [],
[{xmlcdata, "This web page is only informative. "
"To use HTTP-Bind you need a Jabber/XMPP client that supports it."}
]}
]}]}.
%%%----------------------------------------------------------------------
%%% BEHAVIOUR CALLBACKS
+16 -11
View File
@@ -73,7 +73,7 @@
-endif.
-record(state, {host, docroot, accesslog, accesslogfd, directory_indices,
default_content_type, content_types = []}).
custom_headers, default_content_type, content_types = []}).
-define(PROCNAME, ejabberd_mod_http_fileserver).
@@ -141,12 +141,13 @@ start_link(Host, Opts) ->
init([Host, Opts]) ->
try initialize(Host, Opts) of
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
DefaultContentType, ContentTypes} ->
CustomHeaders, DefaultContentType, ContentTypes} ->
{ok, #state{host = Host,
accesslog = AccessLog,
accesslogfd = AccessLogFD,
docroot = DocRoot,
directory_indices = DirectoryIndices,
custom_headers = CustomHeaders,
default_content_type = DefaultContentType,
content_types = ContentTypes}}
catch
@@ -163,12 +164,13 @@ initialize(Host, Opts) ->
AccessLog = gen_mod:get_opt(accesslog, Opts, undefined),
AccessLogFD = try_open_log(AccessLog, Host),
DirectoryIndices = gen_mod:get_opt(directory_indices, Opts, []),
CustomHeaders = gen_mod:get_opt(custom_headers, Opts, []),
DefaultContentType = gen_mod:get_opt(default_content_type, Opts,
?DEFAULT_CONTENT_TYPE),
ContentTypes = build_list_content_types(gen_mod:get_opt(content_types, Opts, []), ?DEFAULT_CONTENT_TYPES),
?INFO_MSG("initialize: ~n ~p", [ContentTypes]),%+++
{DocRoot, AccessLog, AccessLogFD, DirectoryIndices,
DefaultContentType, ContentTypes}.
CustomHeaders, DefaultContentType, ContentTypes}.
%% @spec (AdminCTs::[CT], Default::[CT]) -> [CT]
%% where CT = {Extension::string(), Value}
@@ -231,6 +233,7 @@ try_open_log(FN, Host) ->
%%--------------------------------------------------------------------
handle_call({serve, LocalPath}, _From, State) ->
Reply = serve(LocalPath, State#state.docroot, State#state.directory_indices,
State#state.custom_headers,
State#state.default_content_type, State#state.content_types),
{reply, Reply, State};
handle_call(_Request, _From, State) ->
@@ -298,42 +301,44 @@ process(LocalPath, Request) ->
ejabberd_web:error(not_found)
end.
serve(LocalPath, DocRoot, DirectoryIndices, DefaultContentType, ContentTypes) ->
serve(LocalPath, DocRoot, DirectoryIndices, CustomHeaders, DefaultContentType, ContentTypes) ->
FileName = filename:join(filename:split(DocRoot) ++ LocalPath),
case file:read_file_info(FileName) of
{error, enoent} -> ?HTTP_ERR_FILE_NOT_FOUND;
{error, eacces} -> ?HTTP_ERR_FORBIDDEN;
{ok, #file_info{type = directory}} -> serve_index(FileName,
DirectoryIndices,
CustomHeaders,
DefaultContentType,
ContentTypes);
{ok, FileInfo} -> serve_file(FileInfo, FileName,
CustomHeaders,
DefaultContentType,
ContentTypes)
end.
%% Troll through the directory indices attempting to find one which
%% works, if none can be found, return a 404.
serve_index(_FileName, [], _DefaultContentType, _ContentTypes) ->
serve_index(_FileName, [], _CH, _DefaultContentType, _ContentTypes) ->
?HTTP_ERR_FILE_NOT_FOUND;
serve_index(FileName, [Index | T], DefaultContentType, ContentTypes) ->
serve_index(FileName, [Index | T], CH, DefaultContentType, ContentTypes) ->
IndexFileName = filename:join([FileName] ++ [Index]),
case file:read_file_info(IndexFileName) of
{error, _Error} -> serve_index(FileName, T, DefaultContentType, ContentTypes);
{ok, #file_info{type = directory}} -> serve_index(FileName, T, DefaultContentType, ContentTypes);
{ok, FileInfo} -> serve_file(FileInfo, IndexFileName, DefaultContentType, ContentTypes)
{error, _Error} -> serve_index(FileName, T, CH, DefaultContentType, ContentTypes);
{ok, #file_info{type = directory}} -> serve_index(FileName, T, CH, DefaultContentType, ContentTypes);
{ok, FileInfo} -> serve_file(FileInfo, IndexFileName, CH, DefaultContentType, ContentTypes)
end.
%% Assume the file exists if we got this far and attempt to read it in
%% and serve it up.
serve_file(FileInfo, FileName, DefaultContentType, ContentTypes) ->
serve_file(FileInfo, FileName, CustomHeaders, DefaultContentType, ContentTypes) ->
?DEBUG("Delivering: ~s", [FileName]),
{ok, FileContents} = file:read_file(FileName),
ContentType = content_type(FileName, DefaultContentType, ContentTypes),
{FileInfo#file_info.size,
200, [{"Server", "ejabberd"},
{"Last-Modified", last_modified(FileInfo)},
{"Content-Type", ContentType}],
{"Content-Type", ContentType} | CustomHeaders],
FileContents}.
%%----------------------------------------------------------------------
+60 -25
View File
@@ -2,34 +2,69 @@
INPUT=$1
WAVE1_AMPLITUDE=$((2 + $RANDOM % 5))
WAVE1_LENGTH=$((50 + $RANDOM % 25))
WAVE2_AMPLITUDE=$((2 + $RANDOM % 5))
WAVE2_LENGTH=$((50 + $RANDOM % 25))
WAVE3_AMPLITUDE=$((2 + $RANDOM % 5))
WAVE3_LENGTH=$((50 + $RANDOM % 25))
W1_LINE_START_Y=$((10 + $RANDOM % 40))
W1_LINE_STOP_Y=$((10 + $RANDOM % 40))
W2_LINE_START_Y=$((10 + $RANDOM % 40))
W2_LINE_STOP_Y=$((10 + $RANDOM % 40))
W3_LINE_START_Y=$((10 + $RANDOM % 40))
W3_LINE_STOP_Y=$((10 + $RANDOM % 40))
if test -n ${BASH_VERSION:-''} ; then
get_random ()
{
R=$RANDOM
}
else
for n in `od -A n -t u2 -N 48 /dev/urandom`; do RL="$RL$n "; done
get_random ()
{
R=${RL%% *}
RL=${RL#* }
}
fi
B1_LINE_START_Y=$(($RANDOM % 40))
B1_LINE_STOP_Y=$(($RANDOM % 40))
B2_LINE_START_Y=$(($RANDOM % 40))
B2_LINE_STOP_Y=$(($RANDOM % 40))
#B3_LINE_START_Y=$(($RANDOM % 40))
#B3_LINE_STOP_Y=$(($RANDOM % 40))
get_random
WAVE1_AMPLITUDE=$((2 + $R % 5))
get_random
WAVE1_LENGTH=$((50 + $R % 25))
get_random
WAVE2_AMPLITUDE=$((2 + $R % 5))
get_random
WAVE2_LENGTH=$((50 + $R % 25))
get_random
WAVE3_AMPLITUDE=$((2 + $R % 5))
get_random
WAVE3_LENGTH=$((50 + $R % 25))
get_random
W1_LINE_START_Y=$((10 + $R % 40))
get_random
W1_LINE_STOP_Y=$((10 + $R % 40))
get_random
W2_LINE_START_Y=$((10 + $R % 40))
get_random
W2_LINE_STOP_Y=$((10 + $R % 40))
get_random
W3_LINE_START_Y=$((10 + $R % 40))
get_random
W3_LINE_STOP_Y=$((10 + $R % 40))
B1_LINE_START_X=$(($RANDOM % 20))
B1_LINE_STOP_X=$((100 + $RANDOM % 40))
B2_LINE_START_X=$(($RANDOM % 20))
B2_LINE_STOP_X=$((100 + $RANDOM % 40))
#B3_LINE_START_X=$(($RANDOM % 20))
#B3_LINE_STOP_X=$((100 + $RANDOM % 40))
get_random
B1_LINE_START_Y=$(($R % 40))
get_random
B1_LINE_STOP_Y=$(($R % 40))
get_random
B2_LINE_START_Y=$(($R % 40))
get_random
B2_LINE_STOP_Y=$(($R % 40))
#B3_LINE_START_Y=$(($R % 40))
#B3_LINE_STOP_Y=$(($R % 40))
ROLL_X=$(($RANDOM % 40))
get_random
B1_LINE_START_X=$(($R % 20))
get_random
B1_LINE_STOP_X=$((100 + $R % 40))
get_random
B2_LINE_START_X=$(($R % 20))
get_random
B2_LINE_STOP_X=$((100 + $R % 40))
#B3_LINE_START_X=$(($R % 20))
#B3_LINE_STOP_X=$((100 + $R % 40))
get_random
ROLL_X=$(($R % 40))
convert -size 180x60 xc:none -pointsize 40 \
\( -clone 0 -fill white \