2005-05-23 Alexey Shchepin <alexey@sevcom.net>
+ * src/mod_last_odbc.erl: Added store_last_info/4 function (thanks
+ to Sergei Golovan)
+ * src/mod_last.erl: Likewise
+
+ * src/jd2ejd.erl: Support for exporting iq:last information,
+ better error handling (thanks to Sergei Golovan)
+
+ * src/ejabberd_ctl.erl: Added "import-file" and "import-dir"
+ commands (thanks to Sergei Golovan)
+
* doc/guide.tex: Updated (thanks to Sergei Golovan)
* doc/dev.tex: Likewise
* doc/disco.png: Likewise
<A NAME="sec:intro"></A>
<TT>ejabberd</TT> is a Free and Open Source fault-tolerant distributed Jabber
-server. It is writen mostly in Erlang.<BR>
+server. It is written mostly in Erlang.<BR>
<BR>
-The main features of <TT>ejabberd</TT> is:
+The main features of <TT>ejabberd</TT> are:
<UL><LI>
-Works on most of popular platforms: *nix (tested on Linux and FreeBSD)
- and Win32
-<LI>Distributed: You can run <TT>ejabberd</TT> on a cluster of machines and all of
- them will serve one Jabber domain.
+Works on most of popular platforms: *nix (tested on Linux, FreeBSD and
+ NetBSD) and Win32
+<LI>Distributed: You can run <TT>ejabberd</TT> on a cluster of machines to let all of
+ them serve one Jabber domain.
<LI>Fault-tolerance: You can setup an <TT>ejabberd</TT> cluster so that all the
information required for a properly working service will be stored
permanently on more than one node. This means that if one of the nodes
crashes, then the others will continue working without disruption.
- You can also add or replace more nodes ``on the fly''.
-<LI>Built-in <A HREF="http://www.jabber.org/jeps/jep-0045.html">Multi-User
- Chat</A> service
+ You can also add or replace nodes ``on the fly''.
+<LI>Support for virtual hosting
+<LI>Built-in <A HREF="http://www.jabber.org/jeps/jep-0045.html">Multi-User Chat</A> service
<LI>Built-in IRC transport
-<LI>Built-in
- <A HREF="http://www.jabber.org/jeps/jep-0060.html">Publish-Subscribe</A>
- service
+<LI>Built-in <A HREF="http://www.jabber.org/jeps/jep-0060.html">Publish-Subscribe</A> service
<LI>Built-in Jabber Users Directory service based on users vCards
-<LI>Support for
- <A HREF="http://www.jabber.org/jeps/jep-0030.html">JEP-0030</A>
- (Service Discovery).
-<LI>Support for
- <A HREF="http://www.jabber.org/jeps/jep-0039.html">JEP-0039</A>
- (Statistics Gathering).
-<LI>Support for <TT>xml:lang</TT> attribute in many XML elements
+<LI>Built-in web-based administration interface
+<LI>Built-in <A HREF="http://www.jabber.org/jeps/jep-0025.html">HTTP Polling</A> service
+<LI>SSL support
+<LI>Support for LDAP authentication
+<LI>Ability to interface with external components (JIT, MSN-t, Yahoo-t, etc.)
+<LI>Migration from jabberd14 is possible
+<LI>Mostly XMPP-compliant
+<LI>Support for <A HREF="http://www.jabber.org/jeps/jep-0030.html">Service Discovery</A>.
+<LI>Support for <A HREF="http://www.jabber.org/jeps/jep-0039.html">Statistics Gathering</A>.
+<LI>Support for <TT>xml:lang</TT>
</UL>
+<TT>ejabberd</TT> is a Free and Open Source fault-tolerant distributed Jabber
+server. It is written mostly in Erlang.<BR>
+<BR>
<!--TOC subsection How it works-->
<H3><A NAME="htoc2">1.1</A> How it works</H3><!--SEC END -->
CDATA = {xmlcdata, string()}
</PRE>E. g. this stanza:
<PRE>
-<message to='test@conference.e.localhost' type='groupchat'>
+<message to='test@conference.example.org' type='groupchat'>
<body>test</body>
</message>
</PRE>represented as following structure:
<PRE>
{xmlelement, "message",
- [{"to", "test@conference.e.localhost"},
+ [{"to", "test@conference.example.org"},
{"type", "groupchat"}],
[{xmlelement, "body",
[],
<HEAD><TITLE>Ejabberd Installation and Operation Guide</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=ISO8859-1">
-<META name="GENERATOR" content="hevea 1.07">
+<META name="GENERATOR" content="hevea 1.06">
</HEAD>
<BODY >
<!--HEVEA command line is: /usr/bin/hevea -charset ISO8859-1 guide.tex -->
<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>
-<H3 ALIGN=center>April 18, 2005</H3><DIV ALIGN=center>
+<H3 ALIGN=center>May 23, 2005</H3><DIV ALIGN=center>
<IMG SRC="logo.png">
<LI>Ability to interface with external components (JIT, MSN-t, Yahoo-t, etc.)
<LI>Migration from jabberd14 is possible
<LI>Mostly XMPP-compliant
-<LI>Support for <A HREF="http://www.jabber.org/jeps/jep-0030.html">JEP-0030</A> (Service Discovery).
-<LI>Support for <A HREF="http://www.jabber.org/jeps/jep-0039.html">JEP-0039</A> (Statistics Gathering).
+<LI>Support for <A HREF="http://www.jabber.org/jeps/jep-0030.html">Service Discovery</A>.
+<LI>Support for <A HREF="http://www.jabber.org/jeps/jep-0039.html">Statistics Gathering</A>.
<LI>Support for <TT>xml:lang</TT>
</UL>
The misfeatures of <TT>ejabberd</TT> are:
</PRE><DT><B><TT>{user_regexp, <regexp>, <server>}</TT></B><DD> Matches user with name
that matches <TT><regexp></TT> and from server <TT><server></TT>. Example:
<PRE>
-{acl, tests, {user, "^test", "localhost"}}.
+{acl, tests, {user, "^test", "example.org"}}.
</PRE><DT><B><TT>{server_regexp, <regexp>}</TT></B><DD> Matches any JID from server that
matches <TT><regexp></TT>. Example:
<PRE>
<BR>
The following options are defined:
<DL COMPACT=compact><DT>
- <B><TT>http_poll</TT></B><DD> This option enables <A HREF="http://www.jabber.org/jeps/jep-0025.html">HTTP Polling</A>
+ <B><TT>http_poll</TT></B><DD> This option enables <A HREF="http://www.jabber.org/jeps/jep-0025.html">JEP-0025</A> (HTTP Polling)
support. It is available then at <CODE>http://server:port/http-poll/</CODE>.<BR>
<BR>
<DT><B><TT>web_admin</TT></B><DD> This option enables web-based interface for <TT>ejabberd</TT>
{mod_vcard, []},
{mod_offline, []},
{mod_announce, [{access, announce}]},
- {mod_echo, [{host, "echo.localhost"}]},
+ {mod_echo, [{host, "echo.example.org"}]},
{mod_private, []},
{mod_irc, []},
{mod_muc, []},
but writing will be slower. And of course if machine with one of
replicas is down, other replicas will be used.<BR>
<BR>
-Also section ``5.3 Table Fragmentation''
- <A HREF="http://www.erlang.se/doc/doc-5.4/lib/mnesia-4.2/doc/html/index.html">here</A>
- can be useful.<BR>
+Also section 5.3 (Table Fragmentation) of
+ <A HREF="http://www.erlang.se/doc/doc-5.4/lib/mnesia-4.2/doc/html/index.html">Mnesia Reference Manual</A> can be useful.<BR>
<BR>
(alt) Same as in previous item, but for other tables.<BR>
<BR>
E. g. on figure <A HREF="#fig:discorus">2</A> showed the reply on the following query:
<PRE>
<iq id='5'
- to='e.localhost'
+ to='example.org'
type='get'
xml:lang='ru'>
<query xmlns='http://jabber.org/protocol/disco#items'/>
\author{Alexey Shchepin \\
\ahrefurl{mailto:alexey@sevcom.net} \\
\ahrefurl{xmpp:aleksey@jabber.ru}}
-\date{April 18, 2005}
+\date{May 23, 2005}
\begin{document}
\begin{titlepage}
?STATUS_BADRPC
end;
+process(Node, ["import-file", Path]) ->
+ case rpc:call(Node, jd2ejd, import_file, [Path]) of
+ ok ->
+ ?STATUS_SUCCESS;
+ {error, Reason} ->
+ io:format("Can't import jabberd 1.4 spool file ~p at node ~p: ~p~n",
+ [filename:absname(Path), Node, Reason]),
+ ?STATUS_ERROR;
+ {badrpc, Reason} ->
+ io:format("Can't import jabberd 1.4 spool file ~p at node ~p: ~p~n",
+ [filename:absname(Path), Node, Reason]),
+ ?STATUS_BADRPC
+ end;
+
+process(Node, ["import-dir", Path]) ->
+ case rpc:call(Node, jd2ejd, import_dir, [Path]) of
+ ok ->
+ ?STATUS_SUCCESS;
+ {error, Reason} ->
+ io:format("Can't import jabberd 1.4 spool dir ~p at node ~p: ~p~n",
+ [filename:absname(Path), Node, Reason]),
+ ?STATUS_ERROR;
+ {badrpc, Reason} ->
+ io:format("Can't import jabberd 1.4 spool dir ~p at node ~p: ~p~n",
+ [filename:absname(Path), Node, Reason]),
+ ?STATUS_BADRPC
+ end;
+
process(Node, ["registered-users"]) ->
case rpc:call(Node, ejabberd_auth, dirty_get_registered_users, []) of
Users when is_list(Users) ->
" restart\t\t\trestart ejabberd~n"
" reopen-log\t\t\treopen log file~n"
" register user server password\tregister a user~n"
- " unregister user server\t\tunregister a user~n"
- " backup file\t\t\tstore a database backup in file~n"
+ " unregister user server\tunregister a user~n"
+ " backup file\t\t\tstore a database backup to file~n"
" restore file\t\t\trestore a database backup from file~n"
" install-fallback file\t\tinstall a database fallback from file~n"
- " dump file\t\t\tdump a database in a text file~n"
+ " dump file\t\t\tdump a database to a text file~n"
" load file\t\t\trestore a database from a text file~n"
+ " import-file file\t\timport user data from jabberd 1.4 spool file~n"
+ " import-dir dir\t\timport user data from jabberd 1.4 spool directory~n"
" registered-users\t\tlist all registered users~n"
" delete-expired-messages\tdelete expired offline messages from database~n"
"~n"
{'EXIT', Reason} ->
?ERROR_MSG(
"Error while processing file \"~s\": ~p~n",
- [File, Reason]);
+ [File, Reason]),
+ {error, Reason};
_ ->
ok
end;
{error, Reason} ->
?ERROR_MSG("Can't parse file \"~s\": ~p~n",
- [File, Reason])
+ [File, Reason]),
+ {error, Reason}
end;
{error, Reason} ->
- ?ERROR_MSG("Can't read file \"~s\": ~p~n", [File, Reason])
+ ?ERROR_MSG("Can't read file \"~s\": ~p~n", [File, Reason]),
+ {error, Reason}
end;
false ->
- ?ERROR_MSG("Incorrect user/server name in file \"~s\"~n", [File])
+ ?ERROR_MSG("Illegal user/server name in file \"~s\"~n", [File]),
+ {error, "illegal user/server"}
end.
false
end
end, Files),
- lists:foreach(
- fun(FN) ->
- import_file(filename:join([Dir, FN]))
- end, MsgFiles),
- ok.
+ lists:foldl(
+ fun(FN, A) ->
+ Res = import_file(filename:join([Dir, FN])),
+ case {A, Res} of
+ {ok, ok} -> ok;
+ {ok, _} -> {error, "see ejabberd log for details"};
+ _ -> A
+ end
+ end, ok, MsgFiles).
%%%----------------------------------------------------------------------
%%% Internal functions
?NS_ROSTER ->
catch mod_roster:set_items(User, Server, El),
ok;
+ ?NS_LAST ->
+ TimeStamp = xml:get_attr_s("last", Attrs),
+ Status = xml:get_tag_cdata(El),
+ catch mod_last:store_last_info(User,
+ Server,
+ list_to_integer(TimeStamp),
+ Status),
+ ok;
?NS_VCARD ->
catch mod_vcard:process_sm_iq(
From,
process_local_iq/3,
process_sm_iq/3,
on_presence_update/4,
+ store_last_info/4,
remove_user/2]).
-include("ejabberd.hrl").
on_presence_update(User, Server, _Resource, Status) ->
+ {MegaSecs, Secs, _MicroSecs} = now(),
+ TimeStamp = MegaSecs * 1000000 + Secs,
+ store_last_info(User, Server, TimeStamp, Status).
+
+store_last_info(User, Server, TimeStamp, Status) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
- {MegaSecs, Secs, _MicroSecs} = now(),
- TimeStamp = MegaSecs * 1000000 + Secs,
F = fun() ->
mnesia:write(#last_activity{us = US,
timestamp = TimeStamp,
status = Status})
end,
mnesia:transaction(F).
-
+
remove_user(User, Server) ->
LUser = jlib:nodeprep(User),
stop/0,
process_local_iq/3,
process_sm_iq/3,
- on_presence_update/3,
+ on_presence_update/4,
+ store_last_info/4,
remove_user/1]).
-include("ejabberd.hrl").
-on_presence_update(User, _Resource, Status) ->
- LUser = jlib:nodeprep(User),
+on_presence_update(User, Server, _Resource, Status) ->
{MegaSecs, Secs, _MicroSecs} = now(),
TimeStamp = MegaSecs * 1000000 + Secs,
+ store_last_info(User, Server, TimeStamp, Status).
+
+store_last_info(User, Server, TimeStamp, Status) ->
+ LUser = jlib:nodeprep(User),
Username = ejabberd_odbc:escape(LUser),
Seconds = ejabberd_odbc:escape(integer_to_list(TimeStamp)),
State = ejabberd_odbc:escape(Status),