24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-06-06 21:37:17 +02:00

Merge from trunk (r1563 to r1613).

PR:		EJABP-1

SVN Revision: 1614
This commit is contained in:
Jean-Sébastien Pédron 2008-10-08 12:02:30 +00:00
parent aaecdc4b8a
commit 67a87af459
34 changed files with 1106 additions and 560 deletions

View File

@ -1,3 +1,7 @@
2008-10-08 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
Merge from trunk (r1563 to r1613).
2008-10-07 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/ejabberd_local.erl: Fix a bug where an error stanza was not
@ -9,6 +13,10 @@
* src/mod_private.erl, src/mod_private_odbc.erl, src/mod_version.erl:
Convert to exmpp. Thanks to Pablo Polvorin!
2008-10-07 Jerome Sautret <jerome.sautret@process-one.net>
* src/mod_roster_odbc.erl: fix MySQL multiple requests issue.
2008-10-06 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/ejabberd_sm.erl (process_iq/3): Fix a bug where we were matching
@ -32,6 +40,29 @@
mixing lists and binaries in a non-working way. Thanks to Pablo
Polvorin!
2008-10-06 Badlop <badlop@process-one.net>
* doc/guide.html: Regenerated
2008-10-06 Jerome Sautret <jerome.sautret@process-one.net>
* src/ejabberd_rdbms.erl: fix SQL database reconnection
issues (EJAB-764) and add odbc_start_interval configuration
directive (default to 30 seconds).
* src/odbc/ejabberd_odbc.erl: likewise.
* src/odbc/ejabberd_odbc_sup.erl: likewise.
* doc/guide.tex: likewise.
2008-10-03 Jerome Sautret <jerome.sautret@process-one.net>
* src/odbc/odbc_queries.erl: Fix empty query that fail on MySQL.
2008-10-03 Jerome Sautret <jerome.sautret@process-one.net>
* src/mod_vcard_odbc: added vCard support for MS SQL Server 2005.
* src/odbc/odbc_queries.erl: likewise.
* src/odbc/mssql2005.sql: likewise.
2008-10-02 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/mod_roster_odbc.erl: Fix a bug where a JID represented as a
@ -59,6 +90,17 @@
src/mod_roster_odbc.erl: Fix multiple bugs in ODBC mods, thanks to
Pablo Polvorin!
2008-10-01 Mickael Remond <mremond@process-one.net>
* src/mod_shared_roster.erl: Correct roster push when changing
a shared roster entry name (EJAB-738).
2008-09-30 Badlop <badlop@process-one.net>
* src/*/Makefile.win32: Provide explicit beam filenames because
nmake does not accept wildcards (thanks to Attila
Vangel)(EJAB-543)
2008-09-29 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/jlib.erl (parse_xdata_submit, parse_xdata_fields): Fix a bug
@ -99,6 +141,25 @@
Ejabberd expects new structures. Add table conversion. Add try/catch
block around exmpp_stringprep:*prep/1 uses.
2008-09-24 Christophe Romain <christophe.romain@process-one.net>
* src/mod_pubsub/mod_pubsub.erl: Allow PEP node type to be mapped with
namespace (EJAB-739). Change get_items to use From (EJAB-751). (Thanks
to Eric Cestari)
* src/mod_pubsub/gen_pubsub_node.erl: Likewise
* src/mod_pubsub/node_dispatch.erl: Likewise
* src/mod_pubsub/node_buddy.erl: Likewise
* src/mod_pubsub/node_zoo.erl: Likewise
* src/mod_pubsub/node.template: Likewise
* src/mod_pubsub/node_private.erl: Likewise
* src/mod_pubsub/node_public.erl: Likewise
* src/mod_pubsub/node_default.erl: Likewise
* src/mod_pubsub/node_pep.erl: Likewise
* src/mod_pubsub/node_club.erl: Likewise
* src/mod_pubsub/node_mb.erl: Added PEP microglobing node (Thanks to
Eric Cestari)
2008-09-23 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/mod_vcard.erl (process_sm_iq): Fix a bug where a badmatch
@ -126,6 +187,11 @@
* src/mod_vcard_ldap.erl, src/mod_vcard_odbc.erl: Convert to exmpp.
2008-09-22 Mickael Remond <mremond@process-one.net>
* src/mod_configure.erl: Fix adhoc commands reply types for
"get-online-users-num" and "get-registered-users-num" (EJAB-756).
2008-09-18 Jean-Sébastien Pédron <js.pedron@meetic-corp.com>
* src/mod_roster_odbc.erl: Convert to exmpp.

View File

@ -514,7 +514,7 @@ indicates you need to also update those tables.</P><P> <A NAME="configure"></A>
<H2 CLASS="section"><!--SEC ANCHOR --><A NAME="htoc20">3.1</A>&#XA0;&#XA0;<A HREF="#basicconfig">Basic Configuration</A></H2><!--SEC END --><P> <A NAME="basicconfig"></A> </P><P>The configuration file will be loaded the first time you start <TT>ejabberd</TT>. The
content from this file will be parsed and stored in the internal <TT>ejabberd</TT> database. Subsequently the
configuration will be loaded from the database and any commands in the
configuration file are appended to the entries in the database. </P><P>Note that <TT>ejabberd</TT> never edits the configuration file.
configuration file are appended to the entries in the database.</P><P>Note that <TT>ejabberd</TT> never edits the configuration file.
So, the configuration changes done using the Web Admin
are stored in the database, but are not reflected in the configuration file.
If you want those changes to be use after <TT>ejabberd</TT> restart, you can either
@ -635,7 +635,7 @@ Handles c2s connections.<BR>
Handles incoming s2s connections.<BR>
Options: <TT>inet6</TT>, <TT>ip</TT>, <TT>max_stanza_size</TT>
</DD><DT CLASS="dt-description"><B><TT>ejabberd_service</TT></B></DT><DD CLASS="dd-description">
Interacts with <A HREF="http://www.ejabberd.im/tutorials-transports">external components</A>
Interacts with an <A HREF="http://www.ejabberd.im/tutorials-transports">external component</A>
(as defined in the Jabber Component Protocol (<A HREF="http://www.xmpp.org/extensions/xep-0114.html">XEP-0114</A>).<BR>
Options: <TT>access</TT>, <TT>hosts</TT>, <TT>inet6</TT>,
<TT>ip</TT>, <TT>shaper</TT>, <TT>service_check_from</TT>
@ -655,9 +655,10 @@ used to disable control on the from field on packets send by an
external components. The option can be either <TT>true</TT> or
<TT>false</TT>. The default value is <TT>true</TT> which conforms to <A HREF="http://www.xmpp.org/extensions/xep-0114.html">XEP-0114</A>.
</DD><DT CLASS="dt-description"><B><TT>{hosts, [Hostnames], [HostOptions]}</TT></B></DT><DD CLASS="dd-description">
This option of <TT>ejabberd_service</TT> allows to define one or more hostnames
of external Jabber components that provide a service.
In <TT>HostOptions</TT> it is possible to define the password required to those components
The external Jabber component that connects to this <TT>ejabberd_service</TT>
can serve one or more hostnames.
In <TT>HostOptions</TT> you can define options for the component;
currently the only allowed option is the password required to the component
when attempt to connect to ejabberd: <TT>{password, Secret}</TT>.
Note that you cannot define in a single <TT>ejabberd_service</TT> components of
different services: add an <TT>ejabberd_service</TT> for each service,
@ -1261,6 +1262,9 @@ to keep alive the connections to the database.
The default value is &#X2019;undefined&#X2019;, so no keepalive requests are made.
Specify in seconds: for example 28800 means 8 hours.
</P><PRE CLASS="verbatim">{odbc_keepalive_interval, undefined}.
</PRE><P>If the connection to the database fails, <TT>ejabberd</TT> waits 30 seconds before retrying.
You can modify this interval with this option:
</P><PRE CLASS="verbatim">{odbc_start_interval, 30}.
</PRE><P> <A NAME="compilemysql"></A> </P><!--TOC subsubsection Driver Compilation-->
<H4 CLASS="subsubsection"><!--SEC ANCHOR --><A HREF="#compilemysql">Driver Compilation</A></H4><!--SEC END --><P> <A NAME="compilemysql"></A>
</P><P>You can skip this step if you installed <TT>ejabberd</TT> using a binary installer or
@ -2055,7 +2059,9 @@ change nickname.
status text in presence updates. If disallowed, the <TT>status</TT>
text is stripped before broadcasting the presence update to all
the room occupants.
</DD><DT CLASS="dt-description"><B><TT>{anonymous, true}</TT></B></DT><DD CLASS="dd-description"> Occupants are allowed to see the real JIDs of other occupants.
</DD><DT CLASS="dt-description"><B><TT>{anonymous, true}</TT></B></DT><DD CLASS="dd-description"> The room is anonymous:
occupants don&#X2019;t see the real JIDs of other occupants.
Note that the room moderators can always see the real JIDs of the occupants.
</DD><DT CLASS="dt-description"><B><TT>{logging, false}</TT></B></DT><DD CLASS="dd-description"> The public messages are logged using <TT>mod_muc_log</TT>.
</DD><DT CLASS="dt-description"><B><TT>{max_users, 200}</TT></B></DT><DD CLASS="dd-description"> Maximum number of occupants in the room.
</DD><DT CLASS="dt-description"><B><TT>{members_by_default, true}</TT></B></DT><DD CLASS="dd-description"> The occupants that enter the room are participants by default, so they have &#X2019;voice&#X2019;.
@ -3184,11 +3190,15 @@ 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;
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/" \
-mnesia extra_db_nodes "['ejabberd@first']" \
-s mnesia
</PRE><P>This will start Mnesia serving the same database as <TT>ejabberd@first</TT>.
You can check this by running the command &#X2018;<CODE>mnesia:info().</CODE>&#X2019;. You
should see a lot of remote tables and a line like the following:</P><PRE CLASS="verbatim">running db nodes = [ejabberd@first, ejabberd@second]
should see a lot of remote tables and a line like the following:</P><P>Note: the Mnesia directory may be different in your system.
To know where does ejabberd expect Mnesia to be installed by default,
call <A HREF="#ejabberdctl">4.1</A> without options and it will show some help,
including the Mnesia database spool dir.</P><PRE CLASS="verbatim">running db nodes = [ejabberd@first, ejabberd@second]
</PRE></LI><LI CLASS="li-enumerate">Now run the following in the same &#X2018;<TT>erl</TT>&#X2019; session:<PRE CLASS="verbatim">mnesia:change_table_copy_type(schema, node(), disc_copies).
</PRE><P>This will create local disc storage for the database.</P><P>(alt) Change storage type of the <TT>scheme</TT> table to &#X2018;RAM and disc
copy&#X2019; on the second node via the Web Admin.</P></LI><LI CLASS="li-enumerate">Now you can add replicas of various tables to this node with

View File

@ -1617,6 +1617,13 @@ Specify in seconds: for example 28800 means 8 hours.
{odbc_keepalive_interval, undefined}.
\end{verbatim}
If the connection to the database fails, \ejabberd{} waits 30 seconds before retrying.
You can modify this interval with this option:
\begin{verbatim}
{odbc_start_interval, 30}.
\end{verbatim}
\makesubsubsection{compilemysql}{Driver Compilation}
\ind{MySQL!Driver Compilation}

View File

@ -52,14 +52,21 @@ start_hosts() ->
%% Start the ODBC module on the given host
start_odbc(Host) ->
Supervisor_name = gen_mod:get_module_proc(Host, ejabberd_odbc_sup),
ChildSpec =
{gen_mod:get_module_proc(Host, ejabberd_odbc_sup),
{Supervisor_name,
{ejabberd_odbc_sup, start_link, [Host]},
temporary,
transient,
infinity,
supervisor,
[ejabberd_odbc_sup]},
supervisor:start_child(ejabberd_sup, ChildSpec).
case supervisor:start_child(ejabberd_sup, ChildSpec) of
{ok, _PID} ->
ok;
_Error ->
?ERROR_MSG("Start of supervisor ~p failed:~n~p~nRetrying...~n", [Supervisor_name, _Error]),
start_odbc(Host)
end.
%% Returns true if we have configured odbc_server for the given host
needs_odbc(Host) ->

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\ejabberd_zlib.beam
SOURCE = ejabberd_zlib_drv.c
OBJECT = ejabberd_zlib_drv.o

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\eldap.beam ..\eldap_filter.beam ..\eldap_pool.beam ..\eldap_utils.beam
ALL : $(BEAMS)

View File

@ -1240,7 +1240,7 @@ get_form(Host, ?NS_ADMINL("get-registered-users-num"), Lang) ->
[#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children =
[?HFIELD(),
#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =
[#xmlattr{name = 'type', value = "jid-single"},
[#xmlattr{name = 'type', value = "text-single"},
#xmlattr{name = 'label', value = ?T(Lang, "Number of registered users")},
#xmlattr{name = 'var', value = "registeredusersnum"}], children =
[#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}]
@ -1252,7 +1252,7 @@ get_form(Host, ?NS_ADMINL("get-online-users-num"), Lang) ->
[#xmlel{ns = ?NS_DATA_FORMS, name = 'x', children =
[?HFIELD(),
#xmlel{ns = ?NS_DATA_FORMS, name = 'field', attrs =
[#xmlattr{name = 'type', value = "jid-single"},
[#xmlattr{name = 'type', value = "text-single"},
#xmlattr{name = 'label', value = ?T(Lang, "Number of online users")},
#xmlattr{name = 'var', value = "onlineusersnum"}], children =
[#xmlel{ns = ?NS_DATA_FORMS, name = 'value', children = [#xmlcdata{cdata = list_to_binary(Num)}]}]

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\iconv.beam ..\mod_irc.beam ..\mod_irc_connection.beam
SOURCE = iconv_erl.c
OBJECT = iconv_erl.o

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\mod_muc.beam ..\mod_muc_log.beam ..\mod_muc_room.beam
ALL : $(BEAMS)

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\mod_proxy65.beam ..\mod_proxy65_lib.beam ..\mod_proxy65_service.beam ..\mod_proxy65_sm.beam ..\mod_proxy65_stream.beam
ALL : $(BEAMS)
@ -19,7 +18,7 @@ $(OUTDIR)\mod_proxy65_service.beam : mod_proxy65_service.erl
erlc -W $(EFLAGS) -o $(OUTDIR) mod_proxy65_service.erl
$(OUTDIR)\mod_proxy65_sm.beam : mod_proxy65_sm.erl
erlc -W $(EFLAGS) -o $(OUTDIR) mod_mod_proxy65_sm.erl
erlc -W $(EFLAGS) -o $(OUTDIR) mod_proxy65_sm.erl
$(OUTDIR)\mod_proxy65_stream.beam : mod_proxy65_stream.erl
erlc -W $(EFLAGS) -o $(OUTDIR) mod_proxy65_stream.erl

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\gen_pubsub_node.beam ..\gen_pubsub_nodetree.beam ..\mod_pubsub.beam ..\nodetree_default.beam ..\nodetree_virtual.beam ..\node_buddy.beam ..\node_club.beam ..\node_default.beam ..\node_dispatch.beam ..\node_pep.beam ..\node_private.beam ..\node_public.beam
ALL : $(BEAMS)
@ -27,9 +26,23 @@ $(OUTDIR)\nodetree_default.beam : nodetree_default.erl
$(OUTDIR)\nodetree_virtual.beam : nodetree_virtual.erl
erlc -W $(EFLAGS) -o $(OUTDIR) nodetree_virtual.erl
$(OUTDIR)\node_buddy.beam : node_buddy.erl
erlc -W $(EFLAGS) -o $(OUTDIR) node_buddy.erl
$(OUTDIR)\node_club.beam : node_club.erl
erlc -W $(EFLAGS) -o $(OUTDIR) node_club.erl
$(OUTDIR)\node_default.beam : node_default.erl
erlc -W $(EFLAGS) -o $(OUTDIR) node_default.erl
$(OUTDIR)\node_dispatch.beam : node_dispatch.erl
erlc -W $(EFLAGS) -o $(OUTDIR) node_dispatch.erl
$(OUTDIR)\node_pep.beam : node_pep.erl
erlc -W $(EFLAGS) -o $(OUTDIR) node_pep.erl
$(OUTDIR)\node_private.beam : node_private.erl
erlc -W $(EFLAGS) -o $(OUTDIR) node_private.erl
$(OUTDIR)\node_public.beam : node_public.erl
erlc -W $(EFLAGS) -o $(OUTDIR) node_public.erl

View File

@ -63,7 +63,7 @@ behaviour_info(callbacks) ->
{get_state, 3},
{set_state, 1},
{get_items, 7},
{get_items, 2},
{get_items, 3},
{get_item, 8},
{get_item, 3},
{set_item, 1},

View File

@ -77,7 +77,8 @@
delete_item/4,
get_configure/4,
set_configure/5,
get_items/2,
get_items/3,
tree_action/3,
node_action/3,
node_action/4
]).
@ -114,6 +115,7 @@
-record(state, {server_host,
host,
access,
pep_mapping = [],
nodetree = ?STDTREE,
plugins = [?STDNODE]}).
@ -175,7 +177,7 @@ init([ServerHost, Opts]) ->
{?NS_PUBSUB, ejabberd_sm, iq_sm},
{?NS_PUBSUB_OWNER, ejabberd_sm, iq_sm}]),
ejabberd_router:register_route(Host),
{Plugins, NodeTree} = init_plugins(Host, ServerHost, Opts),
{Plugins, NodeTree, PepMapping} = init_plugins(Host, ServerHost, Opts),
update_database(Host),
ets:new(gen_mod:get_module_proc(Host, pubsub_state), [set, named_table]),
ets:insert(gen_mod:get_module_proc(Host, pubsub_state), {nodetree, NodeTree}),
@ -183,10 +185,12 @@ init([ServerHost, Opts]) ->
ets:new(gen_mod:get_module_proc(ServerHost, pubsub_state), [set, named_table]),
ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {nodetree, NodeTree}),
ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {plugins, Plugins}),
ets:insert(gen_mod:get_module_proc(ServerHost, pubsub_state), {pep_mapping, PepMapping}),
init_nodes(Host, ServerHost),
{ok, #state{host = Host,
server_host = ServerHost,
access = Access,
pep_mapping = PepMapping,
nodetree = NodeTree,
plugins = Plugins}}.
@ -209,12 +213,14 @@ init_plugins(Host, ServerHost, Opts) ->
?DEBUG("** tree plugin is ~p",[TreePlugin]),
TreePlugin:init(Host, ServerHost, Opts),
Plugins = lists:usort(gen_mod:get_opt(plugins, Opts, []) ++ [?STDNODE]),
PepMapping = lists:usort(gen_mod:get_opt(pep_mapping, Opts, [])),
?DEBUG("** PEP Mapping : ~p~n",[PepMapping]),
lists:foreach(fun(Name) ->
?DEBUG("** init ~s plugin",[Name]),
Plugin = list_to_atom(?PLUGIN_PREFIX ++ Name),
Plugin:init(Host, ServerHost, Opts)
end, Plugins),
{Plugins, TreePlugin}.
{Plugins, TreePlugin, PepMapping}.
terminate_plugins(Host, ServerHost, Plugins, TreePlugin) ->
lists:foreach(fun(Name) ->
@ -371,11 +377,11 @@ disco_sm_items(Acc, _From, To, [], _Lang) ->
{result, NodeItems ++ Items}
end;
disco_sm_items(Acc, _From, To, Node, _Lang) ->
disco_sm_items(Acc, From, To, Node, _Lang) ->
%% TODO, use iq_disco_items(Host, Node, From)
Host = To#jid.lserver,
LJID = jlib:jid_tolower(jlib:jid_remove_resource(To)),
case get_items(Host, Node) of
case get_items(Host, Node, From) of
[] ->
Acc;
AllItems ->
@ -430,6 +436,8 @@ handle_call(server_host, _From, State) ->
{reply, State#state.server_host, State};
handle_call(plugins, _From, State) ->
{reply, State#state.plugins, State};
handle_call(pep_mapping, _From, State) ->
{reply, State#state.pep_mapping, State};
handle_call(nodetree, _From, State) ->
{reply, State#state.nodetree, State};
handle_call(stop, _From, State) ->
@ -717,7 +725,7 @@ node_disco_info(Host, Node, From, Identity, Features) ->
[] ->
["leaf"]; %% No sub-nodes: it's a leaf node
_ ->
case node_call(Type, get_items, [Host, Node]) of
case node_call(Type, get_items, [Host, Node, From]) of
{result, []} -> ["collection"];
{result, _} -> ["leaf", "collection"];
_ -> []
@ -782,7 +790,7 @@ iq_disco_items(Host, Item, From) ->
%% TODO That is, remove name attribute
Action =
fun(#pubsub_node{type = Type}) ->
NodeItems = case node_call(Type, get_items, [Host, Node]) of
NodeItems = case node_call(Type, get_items, [Host, Node, From]) of
{result, I} -> I;
_ -> []
end,
@ -1183,10 +1191,7 @@ create_node(Host, ServerHost, [], Owner, Type, Access, Configuration) ->
{error, extended_error(?ERR_NOT_ACCEPTABLE, "nodeid-required")}
end;
create_node(Host, ServerHost, Node, Owner, GivenType, Access, Configuration) ->
Type = case Host of
{_User, _Server, _Resource} -> ?PEPNODE;
_ -> GivenType
end,
Type = select_type(ServerHost, Host, Node, GivenType),
Parent = lists:sublist(Node, length(Node) - 1),
%% TODO, check/set node_type = Type
ParseOptions = case xml:remove_cdata(Configuration) of
@ -1488,12 +1493,7 @@ publish_item(Host, ServerHost, Node, Publisher, ItemId, Payload) ->
%% handles auto-create feature
%% for automatic node creation. we'll take the default node type:
%% first listed into the plugins configuration option, or pep
Type = case Host of
{_User, _Server, _Resource} ->
?PEPNODE;
_ ->
hd(plugins(ServerHost))
end,
Type = select_type(ServerHost, Host, Node),
case lists:member("auto-create", features(Type)) of
true ->
case create_node(Host, ServerHost, Node, Publisher, Type) of
@ -1712,8 +1712,8 @@ get_items(Host, Node, From, SubId, SMaxItems, ItemIDs) ->
end
end.
get_items(Host, Node) ->
case node_action(Host, Node, get_items, [Host, Node]) of
get_items(Host, Node, From) ->
case node_action(Host, Node, get_items, [Host, Node, From]) of
{result, Items} -> Items;
_ -> []
end.
@ -1723,15 +1723,15 @@ get_items(Host, Node) ->
%% Node = pubsubNode()
%% LJID = {U, S, []}
%% @doc <p>Resend the items of a node to the user.</p>
send_all_items(Host, Node, LJID) ->
send_items(Host, Node, LJID, all).
%send_all_items(Host, Node, LJID) ->
% send_items(Host, Node, LJID, all).
send_last_item(Host, Node, LJID) ->
send_items(Host, Node, LJID, last).
%% TODO use cache-last-item feature
send_items(Host, Node, LJID, Number) ->
ToSend = case get_items(Host, Node) of
ToSend = case get_items(Host, Node, LJID) of
[] ->
[];
Items ->
@ -2411,11 +2411,8 @@ get_configure(Host, Node, From, Lang) ->
end,
transaction(Host, Node, Action, sync_dirty).
get_default(Host, _Node, _From, Lang) ->
Type = case Host of
{_, _, _} -> ?PEPNODE;
_ -> hd(plugins(Host))
end,
get_default(Host, Node, _From, Lang) ->
Type=select_type(Host, Host, Node),
Options = node_options(Type),
{result, [{xmlelement, "pubsub", [{"xmlns", ?NS_PUBSUB_OWNER}],
[{xmlelement, "default", [],
@ -2663,6 +2660,19 @@ plugins(Host) ->
[{plugins, PL}] -> PL;
_ -> [?STDNODE]
end.
select_type(ServerHost, Host, Node, Type)->
?DEBUG("SELECT_TYPE : ~p~n", [Node]),
case Host of
{_User, _Server, _Resource} ->
case ets:lookup(gen_mod:get_module_proc(ServerHost, pubsub_state), pep_mapping) of
[{pep_mapping, PM}] -> ?DEBUG("SELECT_TYPE : ~p~n", [PM]), proplists:get_value(Node, PM,?PEPNODE);
R -> ?DEBUG("SELECT_TYPE why ?: ~p~n", [R]), ?PEPNODE
end;
_ ->
Type
end.
select_type(ServerHost, Host, Node) ->
select_type(ServerHost, Host, Node,hd(plugins(ServerHost))).
features() ->
[
@ -2811,3 +2821,4 @@ uniqid() ->
get_item_name(Host, Node, Id) ->
{result, Name} = node_action(Host, Node, get_item_name, [Host, Node, Id]),
Name.

View File

@ -62,7 +62,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1
@ -168,8 +168,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId)
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

View File

@ -63,7 +63,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -171,8 +171,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

View File

@ -63,7 +63,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -170,8 +170,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

View File

@ -70,7 +70,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -705,9 +705,9 @@ set_state(_) ->
%% relational database), or they can even decide not to persist any items.</p>
%% <p>If a PubSub plugin wants to delegate the item storage to the default node,
%% they can implement this function like this:
%% ```get_items(Host, Node) ->
%% node_default:get_items(Host, Node).'''</p>
get_items(Host, Node) ->
%% ```get_items(Host, Node, From) ->
%% node_default:get_items(Host, Node, From).'''</p>
get_items(Host, Node, _From) ->
Items = mnesia:match_object(
#pubsub_item{itemid = {'_', {Host, Node}}, _ = '_'}),
{result, Items}.
@ -747,7 +747,7 @@ get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, _SubI
%% % Payment is required for a subscription
%% {error, ?ERR_PAYMENT_REQUIRED};
true ->
get_items(Host, Node)
get_items(Host, Node, JID)
end.
%% @spec (Host, Node, ItemId) -> [Item] | []

View File

@ -61,7 +61,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -173,8 +173,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

197
src/mod_pubsub/node_mb.erl Normal file
View File

@ -0,0 +1,197 @@
%%% ====================================================================
%%% ``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-2008, ProcessOne
%%% All Rights Reserved.''
%%% This software is copyright 2006-2008, ProcessOne.
%%%
%%%
%%% @copyright 2006-2008 ProcessOne
%%% @author Eric Cestari <eric@ohmforce.com>
%%% @version {@vsn}, {@date} {@time}
%%% @end
%%% ====================================================================
%%% @doc The module <strong>{@module}</strong> is the pep microblog PubSub plugin.
%%% <p> To be used, mod_pubsub must be configured :
%%% {mod_pubsub, [ % requires mod_caps
%%% {access_createnode, pubsub_createnode},
%%% {plugins, ["default", "pep","mb"]},
%%% {pep_mapping, [{"urn:xmpp:microblog", "mb"}]}
%%% ]},
%%% <p>PubSub plugin nodes are using the {@link gen_pubsub_node} behaviour.</p>
-module(node_mb).
-author('eric@ohmforce.com').
-include("ejabberd.hrl").
-include("pubsub.hrl").
-include("jlib.hrl").
-behaviour(gen_pubsub_node).
%% API definition
-export([init/3, terminate/2,
options/0, features/0,
create_node_permission/6,
create_node/3,
delete_node/2,
purge_node/3,
subscribe_node/8,
unsubscribe_node/5,
publish_item/7,
delete_item/4,
remove_extra_items/4,
get_entity_affiliations/2,
get_node_affiliations/2,
get_affiliation/3,
set_affiliation/4,
get_entity_subscriptions/2,
get_node_subscriptions/2,
get_subscription/3,
set_subscription/4,
get_states/2,
get_state/3,
set_state/1,
get_items/7,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
get_item_name/3
]).
init(Host, ServerHost, Opts) ->
node_pep:init(Host, ServerHost, Opts).
terminate(Host, ServerHost) ->
node_pep:terminate(Host, ServerHost),
ok.
options() ->
[{node_type, pep},
{deliver_payloads, true},
{notify_config, false},
{notify_delete, false},
{notify_retract, false},
{persist_items, true},
{max_items, ?MAXITEMS},
{subscribe, true},
{access_model, presence},
{roster_groups_allowed, []},
{publish_model, publishers},
{max_payload_size, ?MAX_PAYLOAD_SIZE},
{send_last_published_item, on_sub_and_presence},
{deliver_notifications, true},
{presence_based_delivery, true}].
features() ->
["create-nodes", %*
"auto-create", %*
"auto-subscribe", %*
"delete-nodes", %*
"filtered-notifications", %*
"modify-affiliations",
"outcast-affiliation",
"persistent-items",
"publish", %*
"purge-nodes",
"retract-items",
"retrieve-affiliations",
"retrieve-items", %*
"retrieve-subscriptions",
"subscribe" %*
].
create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access) ->
node_pep:create_node_permission(Host, ServerHost, Node, ParentNode, Owner, Access).
create_node(Host, Node, Owner) ->
node_pep:create_node(Host, Node, Owner).
delete_node(Host, Removed) ->
node_pep:delete_node(Host, Removed).
subscribe_node(Host, Node, Sender, Subscriber, AccessModel,
SendLast, PresenceSubscription, RosterGroup) ->
node_pep:subscribe_node(
Host, Node, Sender, Subscriber, AccessModel, SendLast,
PresenceSubscription, RosterGroup).
unsubscribe_node(Host, Node, Sender, Subscriber, SubID) ->
node_pep:unsubscribe_node(Host, Node, Sender, Subscriber, SubID).
publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload) ->
node_pep:publish_item(Host, Node, Publisher, Model, MaxItems, ItemId, Payload).
remove_extra_items(Host, Node, MaxItems, ItemIds) ->
node_pep:remove_extra_items(Host, Node, MaxItems, ItemIds).
delete_item(Host, Node, JID, ItemId) ->
node_pep:delete_item(Host, Node, JID, ItemId).
purge_node(Host, Node, Owner) ->
node_pep:purge_node(Host, Node, Owner).
get_entity_affiliations(Host, Owner) ->
node_pep:get_entity_affiliations(Host, Owner).
get_node_affiliations(Host, Node) ->
node_pep:get_node_affiliations(Host, Node).
get_affiliation(Host, Node, Owner) ->
node_pep:get_affiliation(Host, Node, Owner).
set_affiliation(Host, Node, Owner, Affiliation) ->
node_pep:set_affiliation(Host, Node, Owner, Affiliation).
get_entity_subscriptions(Host,Owner) ->
node_pep:get_entity_subscriptions(Host, Owner).
get_node_subscriptions(Host, Node) ->
node_pep:get_node_subscriptions(Host, Node).
get_subscription(Host,Node,Owner) ->
node_pep:get_subscription(Host,Node,Owner).
set_subscription(Host, Node, Owner, Subscription) ->
node_pep:set_subscription(Host, Node, Owner, Subscription).
get_states(Host, Node) ->
node_pep:get_states(Host, Node).
get_state(Host, Node, JID) ->
node_pep:get_state(Host, Node, JID).
set_state(State) ->
node_pep:set_state(State).
get_items(Host, Node, From) ->
node_pep:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_pep:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
get_item(Host, Node, ItemId) ->
node_pep:get_item(Host, Node, ItemId).
get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_pep:get_item(Host, Node, ItemId, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).
set_item(Item) ->
node_pep:set_item(Item).
get_item_name(Host, Node, Id) ->
node_pep:get_item_name(Host, Node, Id).

View File

@ -59,7 +59,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -123,7 +123,8 @@ create_node_permission(Host, ServerHost, _Node, _ParentNode, Owner, Access) ->
{User, Server, _} -> true;
_ -> false
end;
_ ->
E ->
?DEBUG("Create not allowed : ~p~n", [E]),
false
end
end,
@ -215,8 +216,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

View File

@ -63,7 +63,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -173,8 +173,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

View File

@ -63,7 +63,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -170,8 +170,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

View File

@ -54,7 +54,7 @@
get_state/3,
set_state/1,
get_items/7,
get_items/2,
get_items/3,
get_item/8,
get_item/3,
set_item/1,
@ -163,8 +163,8 @@ get_state(Host, Node, JID) ->
set_state(State) ->
node_default:set_state(State).
get_items(Host, Node) ->
node_default:get_items(Host, Node).
get_items(Host, Node, From) ->
node_default:get_items(Host, Node, From).
get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId) ->
node_default:get_items(Host, Node, JID, AccessModel, PresenceSubscription, RosterGroup, SubId).

View File

@ -638,7 +638,7 @@ set_items(User, Server, #xmlel{children = Els}) ->
LServer = exmpp_stringprep:nameprep(Server),
catch odbc_queries:sql_transaction(
LServer,
lists:map(fun(El) ->
lists:flatmap(fun(El) ->
process_item_set_t(LUser, LServer, El)
end, Els))
catch
@ -1060,4 +1060,3 @@ us_to_list({User, Server}) ->
webadmin_user(Acc, _User, _Server, Lang) ->
Acc ++ [?XE("h3", [?ACT("roster/", "Roster")])].

View File

@ -161,6 +161,7 @@ get_user_roster(Items, US) ->
process_item(RosterItem, Host) ->
USFrom = {UserFrom, ServerFrom} = RosterItem#roster.us,
{UserTo, ServerTo, ResourceTo} = RosterItem#roster.jid,
NameTo = RosterItem#roster.name,
USTo = {UserTo, ServerTo},
DisplayedGroups = get_user_displayed_groups(USFrom),
CommonGroups = lists:filter(fun(Group) ->
@ -188,24 +189,24 @@ process_item(RosterItem, Host) ->
PersonalGroups ->
%% Store roster items in From and To rosters
set_new_rosteritems(UserFrom, ServerFrom,
UserTo, ServerTo, ResourceTo,
UserTo, ServerTo, ResourceTo, NameTo,
PersonalGroups)
end
end.
build_roster_record(User1, Server1, User2, Server2, Groups) ->
build_roster_record(User1, Server1, User2, Server2, Name2, Groups) ->
USR2 = {User2, Server2, undefined},
#roster{usj = {User1, Server1, USR2},
us = {User1, Server1},
jid = USR2,
name = User2,
name = Name2,
subscription = both,
ask = none,
groups = Groups
}.
set_new_rosteritems(UserFrom, ServerFrom,
UserTo, ServerTo, ResourceTo, GroupsFrom) ->
UserTo, ServerTo, ResourceTo, NameTo, GroupsFrom) ->
Mod = case lists:member(mod_roster_odbc,
gen_mod:loaded_modules(ServerFrom)) of
true -> mod_roster_odbc;
@ -213,13 +214,13 @@ set_new_rosteritems(UserFrom, ServerFrom,
end,
RIFrom = build_roster_record(UserFrom, ServerFrom,
UserTo, ServerTo, GroupsFrom),
UserTo, ServerTo, NameTo, GroupsFrom),
set_item(UserFrom, ServerFrom, ResourceTo, RIFrom),
JIDTo = exmpp_jid:make_bare_jid(UserTo, ServerTo),
JIDFrom = exmpp_jid:make_bare_jid(UserFrom, ServerFrom),
RITo = build_roster_record(UserTo, ServerTo,
UserFrom, ServerFrom, []),
UserFrom, ServerFrom, UserFrom,[]),
set_item(UserTo, ServerTo, undefined, RITo),
%% From requests

View File

@ -131,10 +131,7 @@ process_local_iq(_From, _To, #iq{type = set} = IQ_Rec) ->
process_sm_iq(_From, To, #iq{type = get} = IQ_Rec) ->
#jid{lnode = LUser, ldomain = LServer} = To,
Username = ejabberd_odbc:escape(LUser),
case catch ejabberd_odbc:sql_query(
LServer,
["select vcard from vcard "
"where username='", Username, "';"]) of
case catch odbc_queries:get_vcard(LServer, Username) of
{selected, ["vcard"], [{SVCARD}]} ->
try exmpp_xml:parse_document(SVCARD,
[namespace, name_as_atom, autoload_known]) of
@ -233,30 +230,13 @@ set_vcard(User, LServer, VCARD) ->
SOrgUnit = ejabberd_odbc:escape(OrgUnit),
SLOrgUnit = ejabberd_odbc:escape(LOrgUnit),
ejabberd_odbc:sql_transaction(
LServer,
[["delete from vcard where username='", LUsername, "';"],
["insert into vcard(username, vcard) "
"values ('", LUsername, "', '", SVCARD, "');"],
["delete from vcard_search where lusername='", LUsername, "';"],
["insert into vcard_search("
" username, lusername, fn, lfn, family, lfamily,"
" given, lgiven, middle, lmiddle, nickname, lnickname,"
" bday, lbday, ctry, lctry, locality, llocality,"
" email, lemail, orgname, lorgname, orgunit, lorgunit)"
"values (",
" '", Username, "', '", LUsername, "',"
" '", SFN, "', '", SLFN, "',"
" '", SFamily, "', '", SLFamily, "',"
" '", SGiven, "', '", SLGiven, "',"
" '", SMiddle, "', '", SLMiddle, "',"
" '", SNickname, "', '", SLNickname, "',"
" '", SBDay, "', '", SLBDay, "',"
" '", SCTRY, "', '", SLCTRY, "',"
" '", SLocality, "', '", SLLocality, "',"
" '", SEMail, "', '", SLEMail, "',"
" '", SOrgName, "', '", SLOrgName, "',"
" '", SOrgUnit, "', '", SLOrgUnit, "');"]])
odbc_queries:set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail,
SFN, SFamily, SGiven, SLBDay, SLCTRY,
SLEMail, SLFN, SLFamily, SLGiven,
SLLocality, SLMiddle, SLNickname,
SLOrgName, SLOrgUnit, SLocality,
SMiddle, SNickname, SOrgName,
SOrgUnit, SVCARD, Username)
catch
_ ->
{error, badarg}
@ -643,5 +623,3 @@ remove_user(User, Server) ->
LServer,
[["delete from vcard where username='", Username, "';"],
["delete from vcard_search where lusername='", Username, "';"]]).

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\ejabberd_odbc.beam ..\ejabberd_odbc_sup.beam ..\odbc_queries.beam
ALL : $(BEAMS)

View File

@ -30,7 +30,7 @@
-behaviour(gen_server).
%% External exports
-export([start/1, start_link/1,
-export([start/1, start_link/2,
sql_query/2,
sql_query_t/1,
sql_transaction/2,
@ -63,8 +63,8 @@
start(Host) ->
gen_server:start(ejabberd_odbc, [Host], []).
start_link(Host) ->
gen_server:start_link(ejabberd_odbc, [Host], []).
start_link(Host, StartInterval) ->
gen_server:start_link(ejabberd_odbc, [Host, StartInterval], []).
sql_query(Host, Query) ->
gen_server:call(ejabberd_odbc_sup:get_random_pid(Host),
@ -131,10 +131,10 @@ escape_like(C) -> odbc_queries:escape(C).
%% ignore |
%% {stop, Reason}
%%----------------------------------------------------------------------
init([Host]) ->
init([Host, StartInterval]) ->
case ejabberd_config:get_local_option({odbc_keepalive_interval, Host}) of
Interval when is_integer(Interval) ->
timer:apply_interval(Interval*1000, ?MODULE, keep_alive, [self()]);
KeepaliveInterval when is_integer(KeepaliveInterval) ->
timer:apply_interval(KeepaliveInterval*1000, ?MODULE, keep_alive, [self()]);
undefined ->
ok;
_Other ->
@ -144,16 +144,16 @@ init([Host]) ->
case SQLServer of
%% Default pgsql port
{pgsql, Server, DB, Username, Password} ->
pgsql_connect(Server, ?PGSQL_PORT, DB, Username, Password);
pgsql_connect(Server, ?PGSQL_PORT, DB, Username, Password, StartInterval);
{pgsql, Server, Port, DB, Username, Password} when is_integer(Port) ->
pgsql_connect(Server, Port, DB, Username, Password);
pgsql_connect(Server, Port, DB, Username, Password, StartInterval);
%% Default mysql port
{mysql, Server, DB, Username, Password} ->
mysql_connect(Server, ?MYSQL_PORT, DB, Username, Password);
mysql_connect(Server, ?MYSQL_PORT, DB, Username, Password, StartInterval);
{mysql, Server, Port, DB, Username, Password} when is_integer(Port) ->
mysql_connect(Server, Port, DB, Username, Password);
mysql_connect(Server, Port, DB, Username, Password, StartInterval);
_ when is_list(SQLServer) ->
odbc_connect(SQLServer)
odbc_connect(SQLServer, StartInterval)
end.
%%----------------------------------------------------------------------
@ -259,7 +259,7 @@ execute_transaction(State, F, NRestarts) ->
%% part of init/1
%% Open an ODBC database connection
odbc_connect(SQLServer) ->
odbc_connect(SQLServer, StartInterval) ->
application:start(odbc),
case odbc:connect(SQLServer,[{scrollable_cursors, off}]) of
{ok, Ref} ->
@ -268,8 +268,8 @@ odbc_connect(SQLServer) ->
{error, Reason} ->
?ERROR_MSG("ODBC connection (~s) failed: ~p~n",
[SQLServer, Reason]),
%% If we can't connect we wait for 30 seconds before retrying
timer:sleep(30000),
%% If we can't connect we wait before retrying
timer:sleep(StartInterval),
{stop, odbc_connection_failed}
end.
@ -278,15 +278,15 @@ odbc_connect(SQLServer) ->
%% part of init/1
%% Open a database connection to PostgreSQL
pgsql_connect(Server, Port, DB, Username, Password) ->
pgsql_connect(Server, Port, DB, Username, Password, StartInterval) ->
case pgsql:connect(Server, DB, Username, Password, Port) of
{ok, Ref} ->
erlang:monitor(process, Ref),
{ok, #state{db_ref = Ref, db_type = pgsql}};
{error, Reason} ->
?ERROR_MSG("PostgreSQL connection failed: ~p~n", [Reason]),
%% If we can't connect we wait for 30 seconds before retrying
timer:sleep(30000),
%% If we can't connect we wait before retrying
timer:sleep(StartInterval),
{stop, pgsql_connection_failed}
end.
@ -317,7 +317,7 @@ pgsql_item_to_odbc(_) ->
%% part of init/1
%% Open a database connection to MySQL
mysql_connect(Server, Port, DB, Username, Password) ->
mysql_connect(Server, Port, DB, Username, Password, StartInterval) ->
NoLogFun = fun(_Level,_Format,_Argument) -> ok end,
case mysql_conn:start(Server, Port, Username, Password, DB, NoLogFun) of
{ok, Ref} ->
@ -330,9 +330,10 @@ mysql_connect(Server, Port, DB, Username, Password) ->
"SERIALIZABLE;"], self()),
{ok, #state{db_ref = Ref, db_type = mysql}};
{error, Reason} ->
?ERROR_MSG("MySQL connection failed: ~p~n", [Reason]),
%% If we can't connect we wait for 30 seconds before retrying
timer:sleep(30000),
?ERROR_MSG("MySQL connection failed: ~p~nWaiting ~p seconds before retrying...~n",
[Reason, StartInterval div 1000]),
%% If we can't connect we wait before retrying
timer:sleep(StartInterval),
{stop, mysql_connection_failed}
end.

View File

@ -37,13 +37,14 @@
-include("ejabberd.hrl").
-define(DEFAULT_POOL_SIZE, 10).
-define(DEFAULT_ODBC_START_INTERVAL, 30). % 30 seconds
start_link(Host) ->
supervisor:start_link({local, gen_mod:get_module_proc(Host, ?MODULE)},
?MODULE, [Host]).
init([Host]) ->
N = case ejabberd_config:get_local_option({odbc_pool_size, Host}) of
PoolSize = case ejabberd_config:get_local_option({odbc_pool_size, Host}) of
I when is_integer(I) ->
I;
undefined ->
@ -53,16 +54,27 @@ init([Host]) ->
[Other, Host, ?DEFAULT_POOL_SIZE]),
?DEFAULT_POOL_SIZE
end,
{ok, {{one_for_one, 10, 6},
StartInterval = case ejabberd_config:get_local_option({odbc_start_interval, Host}) of
Interval when is_integer(Interval) ->
Interval;
undefined ->
?DEFAULT_ODBC_START_INTERVAL;
_Other2 ->
?ERROR_MSG("Wrong odbc_start_interval definition '~p' for host ~p"
", defaulting to ~p~n",
[_Other2, Host, ?DEFAULT_ODBC_START_INTERVAL]),
?DEFAULT_ODBC_START_INTERVAL
end,
{ok, {{one_for_one, PoolSize+1, StartInterval},
lists:map(
fun(I) ->
{I,
{ejabberd_odbc, start_link, [Host]},
{ejabberd_odbc, start_link, [Host, StartInterval*1000]},
transient,
brutal_kill,
worker,
[?MODULE]}
end, lists:seq(1, N))}}.
end, lists:seq(1, PoolSize))}}.
get_pids(Host) ->
Proc = gen_mod:get_module_proc(Host, ?MODULE),

View File

@ -104,6 +104,10 @@ if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[vcard]') a
drop table [dbo].[vcard]
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[vcard_search]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[vcard_search]
GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[private_storage]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[private_storage]
GO
@ -160,25 +164,35 @@ GO
CREATE TABLE [dbo].[vcard] (
[username] [varchar] (250) NOT NULL ,
[full_name] [varchar] (250) NULL ,
[first_name] [varchar] (50) NULL ,
[last_name] [varchar] (50) NULL ,
[nick_name] [varchar] (50) NULL ,
[url] [varchar] (1024) NULL ,
[address1] [varchar] (50) NULL ,
[address2] [varchar] (50) NULL ,
[locality] [varchar] (50) NULL ,
[region] [varchar] (50) NULL ,
[pcode] [varchar] (50) NULL ,
[country] [varchar] (50) NULL ,
[telephone] [varchar] (50) NULL ,
[email] [varchar] (250) NULL ,
[orgname] [varchar] (50) NULL ,
[orgunit] [varchar] (50) NULL ,
[title] [varchar] (50) NULL ,
[role] [varchar] (50) NULL ,
[b_day] [datetime] NULL ,
[descr] [varchar] (500) NULL
[vcard] [text] NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[vcard_search] (
[username] [varchar] (250) NOT NULL ,
[lusername] [varchar] (250) NOT NULL ,
[fn] [text] NOT NULL ,
[lfn] [varchar] (250) NOT NULL ,
[family] [text] NOT NULL ,
[lfamily] [varchar] (250) NOT NULL ,
[given] [text] NOT NULL ,
[lgiven] [varchar] (250) NOT NULL ,
[middle] [text] NOT NULL ,
[lmiddle] [varchar] (250) NOT NULL ,
[nickname] [text] NOT NULL ,
[lnickname] [varchar] (250) NOT NULL ,
[bday] [text] NOT NULL ,
[lbday] [varchar] (250) NOT NULL ,
[ctry] [text] NOT NULL ,
[lctry] [varchar] (250) NOT NULL ,
[locality] [text] NOT NULL ,
[llocality] [varchar] (250) NOT NULL ,
[email] [text] NOT NULL ,
[lemail] [varchar] (250) NOT NULL ,
[orgname] [text] NOT NULL ,
[lorgname] [varchar] (250) NOT NULL ,
[orgunit] [text] NOT NULL ,
[lorgunit] [varchar] (250) NOT NULL
) ON [PRIMARY]
GO
@ -262,6 +276,31 @@ ALTER TABLE [dbo].[vcard] WITH NOCHECK ADD
) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lfn] ON [dbo].[vcard_search]([lfn]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lfamily] ON [dbo].[vcard_search]([lfamily]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lgiven] ON [dbo].[vcard_search]([lgiven]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lmiddle] ON [dbo].[vcard_search]([lmiddle]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lnickname] ON [dbo].[vcard_search]([lnickname]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lbday] ON [dbo].[vcard_search]([lbday]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lctry] ON [dbo].[vcard_search]([lctry]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_llocality] ON [dbo].[vcard_search]([llocality]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lemail] ON [dbo].[vcard_search]([lemail]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lorgname] ON [dbo].[vcard_search]([lorgname]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE INDEX [IX_vcard_search_lorgunit] ON [dbo].[vcard_search]([lorgunit]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
CREATE CLUSTERED INDEX [IX_rosterusers_user] ON [dbo].[rosterusers]([username]) WITH FILLFACTOR = 90 ON [PRIMARY]
GO
@ -1050,4 +1089,151 @@ END
GO
/******************************************************************/
/****** Object: StoredProcedure [dbo].[set_vcard] **/
/** Set the user's vCard **/
/******************************************************************/
CREATE PROCEDURE [dbo].[set_vcard]
@VCard varchar(8000),
@Username varchar(250),
@Lusername varchar(250),
@Fn varchar(8000),
@Lfn varchar(250),
@Family varchar(8000),
@Lfamily varchar(250),
@Given varchar(8000),
@Lgiven varchar(250),
@Middle varchar(8000),
@Lmiddle varchar(250),
@Nickname varchar(8000),
@Lnickname varchar(250),
@Bday varchar(8000),
@Lbday varchar(250),
@Ctry varchar(8000),
@Lctry varchar(250),
@Locality varchar(8000),
@Llocality varchar(250),
@Email varchar(8000),
@Lemail varchar(250),
@Orgname varchar(8000),
@Lorgname varchar(250),
@Orgunit varchar(8000),
@Lorgunit varchar(250)
AS
BEGIN
IF EXISTS (SELECT username FROM vcard with (nolock) WHERE vcard.username = @Username)
BEGIN
UPDATE [vcard]
SET [vcard].username = @LUsername,
[vcard].vcard = @Vcard
WHERE vcard.username = @LUsername;
UPDATE [vcard_search]
SET [vcard_search].username = @Username,
[vcard_search].lusername = @Lusername,
[vcard_search].fn = @Fn,
[vcard_search].lfn = @Lfn,
[vcard_search].family = @Family,
[vcard_search].lfamily = @Lfamily,
[vcard_search].given = @Given,
[vcard_search].lgiven = @Lgiven,
[vcard_search].middle = @Middle,
[vcard_search].lmiddle = @Lmiddle,
[vcard_search].nickname = @Nickname,
[vcard_search].lnickname = @Lnickname,
[vcard_search].bday = @Bday,
[vcard_search].lbday = @Lbday,
[vcard_search].ctry = @Ctry,
[vcard_search].lctry = @Lctry,
[vcard_search].locality = @Locality,
[vcard_search].llocality = @Llocality,
[vcard_search].email = @Email,
[vcard_search].lemail = @Lemail,
[vcard_search].orgname = @Orgname,
[vcard_search].lorgname = @Lorgname,
[vcard_search].orgunit = @Orgunit,
[vcard_search].lorgunit = @Lorgunit
WHERE vcard_search.lusername = @LUsername;
END
ELSE
BEGIN
INSERT INTO [vcard]
( [vcard].username,
[vcard].vcard
)
VALUES
( @lUsername,
@Vcard
);
INSERT INTO [vcard_search]
(
[vcard_search].username ,
[vcard_search].lusername ,
[vcard_search].fn ,
[vcard_search].lfn ,
[vcard_search].family ,
[vcard_search].lfamily ,
[vcard_search].given ,
[vcard_search].lgiven ,
[vcard_search].middle ,
[vcard_search].lmiddle ,
[vcard_search].nickname,
[vcard_search].lnickname,
[vcard_search].bday,
[vcard_search].lbday,
[vcard_search].ctry,
[vcard_search].lctry,
[vcard_search].locality,
[vcard_search].llocality,
[vcard_search].email,
[vcard_search].lemail,
[vcard_search].orgname,
[vcard_search].lorgname,
[vcard_search].orgunit,
[vcard_search].lorgunit
)
VALUES
(
@Username,
@Lusername,
@Fn,
@Lfn,
@Family,
@Lfamily,
@Given,
@Lgiven,
@Middle,
@Lmiddle,
@Nickname,
@Lnickname,
@Bday,
@Lbday,
@Ctry,
@Lctry,
@Locality,
@Llocality,
@Email,
@Lemail,
@Orgname,
@Lorgname,
@Orgunit,
@Lorgunit
)
END
END
GO
/******************************************************************/
/****** Object: StoredProcedure [dbo].[get_vcard] **/
/** Retrive the user's vCard **/
/******************************************************************/
CREATE PROCEDURE [dbo].[get_vcard]
@Username varchar(250)
AS
BEGIN
SELECT vcard.vcard as vcard
FROM vcard WITH (NOLOCK)
WHERE username=@Username;
END
GO

View File

@ -61,6 +61,8 @@
set_private_data_sql/3,
get_private_data/3,
del_user_private_storage/2,
set_vcard/26,
get_vcard/2,
escape/1,
count_records_where/3]).
@ -327,11 +329,11 @@ update_roster_sql(Username, SJID, ItemVals, ItemGroups) ->
" values (", ItemVals, ");"],
["delete from rostergroups "
" where username='", Username, "' "
" and jid='", SJID, "';"],
" and jid='", SJID, "';"]] ++
[["insert into rostergroups("
" username, jid, grp) "
" values (", ItemGroup, ");"] ||
ItemGroup <- ItemGroups]].
ItemGroup <- ItemGroups].
roster_subscribe(_LServer, Username, SJID, ItemVals) ->
ejabberd_odbc:sql_query_t(
@ -378,6 +380,42 @@ del_user_private_storage(LServer, Username) ->
LServer,
["delete from private_storage where username='", Username, "';"]).
set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality,
SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle,
SNickname, SOrgName, SOrgUnit, SVCARD, Username) ->
ejabberd_odbc:sql_transaction(
LServer,
[["delete from vcard where username='", LUsername, "';"],
["insert into vcard(username, vcard) "
"values ('", LUsername, "', '", SVCARD, "');"],
["delete from vcard_search where lusername='", LUsername, "';"],
["insert into vcard_search("
" username, lusername, fn, lfn, family, lfamily,"
" given, lgiven, middle, lmiddle, nickname, lnickname,"
" bday, lbday, ctry, lctry, locality, llocality,"
" email, lemail, orgname, lorgname, orgunit, lorgunit)"
"values (",
" '", Username, "', '", LUsername, "',"
" '", SFN, "', '", SLFN, "',"
" '", SFamily, "', '", SLFamily, "',"
" '", SGiven, "', '", SLGiven, "',"
" '", SMiddle, "', '", SLMiddle, "',"
" '", SNickname, "', '", SLNickname, "',"
" '", SBDay, "', '", SLBDay, "',"
" '", SCTRY, "', '", SLCTRY, "',"
" '", SLocality, "', '", SLLocality, "',"
" '", SEMail, "', '", SLEMail, "',"
" '", SOrgName, "', '", SLOrgName, "',"
" '", SOrgUnit, "', '", SLOrgUnit, "');"]]).
get_vcard(LServer, Username) ->
ejabberd_odbc:sql_query(
LServer,
["select vcard from vcard "
"where username='", Username, "';"]).
%% Characters to escape
escape($\0) -> "\\0";
escape($\n) -> "\\n";
@ -597,6 +635,25 @@ del_user_private_storage(LServer, Username) ->
LServer,
["EXECUTE dbo.del_user_storage '", Username, "'"]).
set_vcard(LServer, LUsername, SBDay, SCTRY, SEMail, SFN, SFamily, SGiven,
SLBDay, SLCTRY, SLEMail, SLFN, SLFamily, SLGiven, SLLocality,
SLMiddle, SLNickname, SLOrgName, SLOrgUnit, SLocality, SMiddle,
SNickname, SOrgName, SOrgUnit, SVCARD, Username) ->
ejabberd_odbc:sql_query(
LServer,
["EXECUTE dbo.set_vcard '", SVCARD, "' , '", Username, "' , '", LUsername, "' , '",
SFN, "' , '", SLFN, "' , '", SFamily, "' , '", SLFamily, "' , '",
SGiven, "' , '", SLGiven, "' , '", SMiddle, "' , '", SLMiddle, "' , '",
SNickname, "' , '", SLNickname, "' , '", SBDay, "' , '", SLBDay, "' , '",
SCTRY, "' , '", SLCTRY, "' , '", SLocality, "' , '", SLLocality, "' , '",
SEMail, "' , '", SLEMail, "' , '", SOrgName, "' , '", SLOrgName, "' , '",
SOrgUnit, "' , '", SLOrgUnit, "'"]).
get_vcard(LServer, Username) ->
ejabberd_odbc:sql_query(
LServer,
["EXECUTE dbo.get_vcard '", Username, "'"]).
%% Characters to escape
escape($\0) -> "\\0";
escape($\t) -> "\\t";

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\stringprep.beam ..\stringprep_sup.beam
SOURCE = stringprep_drv.c
AUXIL = uni_data.c uni_norm.c

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\tls.beam
SOURCE = tls_drv.c
OBJECT = tls_drv.o

View File

@ -4,8 +4,7 @@ include ..\Makefile.inc
EFLAGS = -I .. -pz ..
OUTDIR = ..
SOURCES = $(wildcard *.erl)
BEAMS = $(addprefix $(OUTDIR)/,$(SOURCES:.erl=.beam))
BEAMS = ..\ejabberd_http.beam ..\ejabberd_http_bind.beam ..\ejabberd_http_poll.beam ..\ejabberd_web.beam ..\ejabberd_web_admin.beam ..\mod_http_bind.beam ..\mod_http_fileserver.beam
ALL : $(BEAMS)
@ -21,5 +20,14 @@ $(OUTDIR)\ejabberd_web.beam : ejabberd_web.erl
$(OUTDIR)\ejabberd_web_admin.beam : ejabberd_web_admin.erl
erlc -W $(EFLAGS) -o $(OUTDIR) ejabberd_web_admin.erl
$(OUTDIR)\ejabberd_http_bind.beam : ejabberd_http_bind.erl
erlc -W $(EFLAGS) -o $(OUTDIR) ejabberd_http_bind.erl
$(OUTDIR)\ejabberd_http_poll.beam : ejabberd_http_poll.erl
erlc -W $(EFLAGS) -o $(OUTDIR) ejabberd_http_poll.erl
$(OUTDIR)\mod_http_bind.beam : mod_http_bind.erl
erlc -W $(EFLAGS) -o $(OUTDIR) mod_http_bind.erl
$(OUTDIR)\mod_http_fileserver.beam : mod_http_fileserver.erl
erlc -W $(EFLAGS) -o $(OUTDIR) mod_http_fileserver.erl