mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-24 17:29:28 +01:00
Cleanup
SVN Revision: 309
This commit is contained in:
parent
2d9b9956b5
commit
e46b28f27f
3
.cvslog
3
.cvslog
@ -1,3 +0,0 @@
|
||||
jabber://aleksey@jabber.ru
|
||||
jabber://sgolovan@nes.ru
|
||||
ryazanov@gmail.com
|
@ -1,3 +1,7 @@
|
||||
2005-04-17 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* (all): Merged virtual hosting support
|
||||
|
||||
2005-04-09 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/ejabberd_c2s.erl: Send new id for each new stream inside one
|
||||
|
86
TODO-vh
86
TODO-vh
@ -1,86 +0,0 @@
|
||||
check remove_user hook
|
||||
|
||||
check all usages of ejabberd_auth
|
||||
|
||||
+ src/ejabberd.hrl -- add MYHOSTS macro to return a list of virtual domains,
|
||||
MYNAME should return first defined host
|
||||
|
||||
? src/acl.erl -- "user", "user_regexp", "user_regexp" should match all virtual
|
||||
domains
|
||||
|
||||
+ src/cyrsasl_digest.erl -- need to use both "username" and "authzid", or better
|
||||
to use callback function
|
||||
|
||||
+ src/cyrsasl_plain.erl -- likewise
|
||||
|
||||
+ src/cyrsasl.erl -- likewise
|
||||
|
||||
+ src/ejabberd_auth.erl -- add "Server" argument to almost all exported
|
||||
functions
|
||||
|
||||
(workaround) src/ejabberd_auth_external.erl -- likewise
|
||||
|
||||
+ src/ejabberd_auth_internal.erl -- likewise
|
||||
|
||||
(workaround) src/ejabberd_auth_ldap.erl -- likewise
|
||||
|
||||
(workaround) src/ejabberd_auth_odbc.erl -- likewise
|
||||
|
||||
+ src/ejabberd_c2s.erl -- add validation of a server field
|
||||
|
||||
+ src/ejabberd_config.erl -- support for "hosts" option
|
||||
|
||||
src/ejabberd_ctl.erl -- add server argument to "register", "unregister", and
|
||||
"registered-users" commands
|
||||
|
||||
+ src/ejabberd_local.erl -- register all virtual hosts in router
|
||||
|
||||
+ src/ejabberd_router.erl -- update dirty_get_all_routes/0
|
||||
|
||||
src/ejabberd_service.erl -- probably minor update in stream header
|
||||
|
||||
+ src/ejabberd_sm.erl -- update "session" and "presence" tables to contain
|
||||
server name in first two fields
|
||||
|
||||
- src/extauth.erl -- same as for src/ejabberd_auth_external.erl
|
||||
|
||||
src/jd2ejd.erl -- anyway need to be rewriten :)
|
||||
|
||||
+ src/mod_announce.erl -- update to ejabberd_auth changes, (-) probably update
|
||||
to send different server names in "from" attribute to users on different
|
||||
virtual hosts
|
||||
|
||||
+ src/mod_configure.erl -- update users part
|
||||
|
||||
+ src/mod_disco.erl -- likewise
|
||||
|
||||
+ src/mod_last.erl -- update db table to store server part of jid
|
||||
|
||||
src/mod_last_odbc.erl -- likewise
|
||||
|
||||
+ src/mod_offline.erl -- likewise
|
||||
|
||||
src/mod_offline_odbc.erl -- likewise
|
||||
|
||||
+ src/mod_privacy.erl -- likewise
|
||||
|
||||
+ src/mod_private.erl -- likewise
|
||||
|
||||
+ src/mod_register.erl -- need to check server field in sender jid and pass it
|
||||
to ejabberd_auth
|
||||
|
||||
(not tested) src/mod_roster.erl -- update db table to store server part of jid
|
||||
|
||||
src/mod_roster_odbc.erl -- update roster_in_subscription,
|
||||
roster_out_subscription, roster_get_subscription_lists hooks
|
||||
|
||||
+ src/mod_vcard.erl -- update db table to store server part of jid
|
||||
|
||||
src/mod_vcard_ldap.erl -- update db table to store server part of jid
|
||||
|
||||
src/mod_pubsub/mod_pubsub.erl -- update defining of "ServedHosts" variable
|
||||
|
||||
+ src/web/ejabberd_web_admin.erl -- update user listing, roster editing, acl
|
||||
setting parts
|
||||
|
||||
+ src/web/ejabberd_web.erl -- update user authorization
|
@ -17,6 +17,7 @@
|
||||
check_password/5,
|
||||
try_register/3,
|
||||
dirty_get_registered_users/0,
|
||||
get_vh_registered_users/1,
|
||||
get_password/2,
|
||||
get_password_s/2,
|
||||
is_user_exists/2,
|
||||
@ -118,7 +119,7 @@ dirty_get_registered_users() ->
|
||||
[]
|
||||
end.
|
||||
|
||||
dirty_get_registered_users(Server) ->
|
||||
get_vh_registered_users(Server) ->
|
||||
dirty_get_registered_users().
|
||||
|
||||
get_password(User, _Server) ->
|
||||
|
@ -445,7 +445,8 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
?INFO_MSG("(~w) Accepted authentication for ~s",
|
||||
[StateData#state.socket, U]),
|
||||
{next_state, wait_for_stream,
|
||||
StateData#state{authentificated = true,
|
||||
StateData#state{streamid = new_id(),
|
||||
authentificated = true,
|
||||
user = U
|
||||
}};
|
||||
{continue, ServerOut, NewSASLState} ->
|
||||
@ -475,6 +476,7 @@ wait_for_feature_request({xmlstreamelement, El}, StateData) ->
|
||||
{next_state, wait_for_stream,
|
||||
StateData#state{sockmod = tls,
|
||||
socket = TLSSocket,
|
||||
streamid = new_id(),
|
||||
tls_enabled = true
|
||||
}};
|
||||
_ ->
|
||||
@ -533,7 +535,8 @@ wait_for_sasl_response({xmlstreamelement, El}, StateData) ->
|
||||
?INFO_MSG("(~w) Accepted authentication for ~s",
|
||||
[StateData#state.socket, U]),
|
||||
{next_state, wait_for_stream,
|
||||
StateData#state{authentificated = true,
|
||||
StateData#state{streamid = new_id(),
|
||||
authentificated = true,
|
||||
user = U
|
||||
}};
|
||||
{continue, ServerOut, NewSASLState} ->
|
||||
|
@ -147,7 +147,7 @@ process(Node, ["load", Path]) ->
|
||||
process(Node, ["restore", Path]) ->
|
||||
case rpc:call(Node,
|
||||
mnesia, restore, [Path, [{default_op, keep_tables}]]) of
|
||||
{atomic, ok} ->
|
||||
{atomic, _} ->
|
||||
?STATUS_SUCCESS;
|
||||
{error, Reason} ->
|
||||
io:format("Can't restore backup from ~p on node ~p: ~p~n",
|
||||
|
@ -146,7 +146,8 @@ clean_table_from_bad_node(Node) ->
|
||||
[{'==', {node, '$1'}, Node}],
|
||||
['$_']}]),
|
||||
lists:foreach(fun(E) ->
|
||||
mnesia:delete_object(E)
|
||||
mnesia:delete_object(E),
|
||||
mnesia:delete({presence, E#session.usr})
|
||||
end, Es)
|
||||
end,
|
||||
mnesia:transaction(F).
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,74 +0,0 @@
|
||||
%% Generated by the Erlang ASN.1 compiler version:1.3.2
|
||||
%% Purpose: Erlang record definitions for each named and unnamed
|
||||
%% SEQUENCE and SET, and macro definitions for each value
|
||||
%% definition,in module ELDAPv3
|
||||
|
||||
|
||||
|
||||
-record('LDAPMessage',{
|
||||
messageID, protocolOp, controls = asn1_NOVALUE}).
|
||||
|
||||
-record('AttributeValueAssertion',{
|
||||
attributeDesc, assertionValue}).
|
||||
|
||||
-record('Attribute',{
|
||||
type, vals}).
|
||||
|
||||
-record('LDAPResult',{
|
||||
resultCode, matchedDN, errorMessage, referral = asn1_NOVALUE}).
|
||||
|
||||
-record('Control',{
|
||||
controlType, criticality = asn1_DEFAULT, controlValue = asn1_NOVALUE}).
|
||||
|
||||
-record('BindRequest',{
|
||||
version, name, authentication}).
|
||||
|
||||
-record('SaslCredentials',{
|
||||
mechanism, credentials = asn1_NOVALUE}).
|
||||
|
||||
-record('BindResponse',{
|
||||
resultCode, matchedDN, errorMessage, referral = asn1_NOVALUE, serverSaslCreds = asn1_NOVALUE}).
|
||||
|
||||
-record('SearchRequest',{
|
||||
baseObject, scope, derefAliases, sizeLimit, timeLimit, typesOnly, filter, attributes}).
|
||||
|
||||
-record('SubstringFilter',{
|
||||
type, substrings}).
|
||||
|
||||
-record('MatchingRuleAssertion',{
|
||||
matchingRule = asn1_NOVALUE, type = asn1_NOVALUE, matchValue, dnAttributes = asn1_DEFAULT}).
|
||||
|
||||
-record('SearchResultEntry',{
|
||||
objectName, attributes}).
|
||||
|
||||
-record('PartialAttributeList_SEQOF',{
|
||||
type, vals}).
|
||||
|
||||
-record('ModifyRequest',{
|
||||
object, modification}).
|
||||
|
||||
-record('ModifyRequest_modification_SEQOF',{
|
||||
operation, modification}).
|
||||
|
||||
-record('AttributeTypeAndValues',{
|
||||
type, vals}).
|
||||
|
||||
-record('AddRequest',{
|
||||
entry, attributes}).
|
||||
|
||||
-record('AttributeList_SEQOF',{
|
||||
type, vals}).
|
||||
|
||||
-record('ModifyDNRequest',{
|
||||
entry, newrdn, deleteoldrdn, newSuperior = asn1_NOVALUE}).
|
||||
|
||||
-record('CompareRequest',{
|
||||
entry, ava}).
|
||||
|
||||
-record('ExtendedRequest',{
|
||||
requestName, requestValue = asn1_NOVALUE}).
|
||||
|
||||
-record('ExtendedResponse',{
|
||||
resultCode, matchedDN, errorMessage, referral = asn1_NOVALUE, responseName = asn1_NOVALUE, response = asn1_NOVALUE}).
|
||||
|
||||
-define('maxInt', 2147483647).
|
@ -808,8 +808,8 @@ filter_presence({xmlelement, "presence", Attrs, Els}) ->
|
||||
case El of
|
||||
{xmlcdata, _} ->
|
||||
false;
|
||||
{xmlelement, Name1, _Attrs1, _Els1} ->
|
||||
XMLNS = xml:get_attr_s("xmlns", Attrs),
|
||||
{xmlelement, Name1, Attrs1, _Els1} ->
|
||||
XMLNS = xml:get_attr_s("xmlns", Attrs1),
|
||||
case {Name1, XMLNS} of
|
||||
{"show", ""} ->
|
||||
true;
|
||||
|
@ -1,404 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : ejabberd_http.erl
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose :
|
||||
%%% Created : 27 Feb 2004 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(ejabberd_http).
|
||||
-author('alexey@sevcom.net').
|
||||
-vsn('$Revision$ ').
|
||||
|
||||
-behaviour(gen_fsm).
|
||||
|
||||
%% External exports
|
||||
-export([start/2,
|
||||
start_link/2]).
|
||||
|
||||
%% gen_fsm callbacks
|
||||
-export([init/1,
|
||||
wait_for_headers/2,
|
||||
handle_event/3,
|
||||
handle_sync_event/4,
|
||||
code_change/4,
|
||||
handle_info/3,
|
||||
terminate/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(DICT, dict).
|
||||
|
||||
-record(state, {socket,
|
||||
request_method,
|
||||
request_path,
|
||||
request_auth
|
||||
}).
|
||||
|
||||
|
||||
-define(DBGFSM, true).
|
||||
|
||||
-ifdef(DBGFSM).
|
||||
-define(FSMOPTS, [{debug, [trace]}]).
|
||||
-else.
|
||||
-define(FSMOPTS, []).
|
||||
-endif.
|
||||
|
||||
-define(XHTML_DOCTYPE,
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
|
||||
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n").
|
||||
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start(SockData, Opts) ->
|
||||
supervisor:start_child(ejabberd_http_sup, [SockData, Opts]).
|
||||
|
||||
start_link(SockData, Opts) ->
|
||||
gen_fsm:start_link(ejabberd_http, [SockData, Opts], ?FSMOPTS).
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Callback functions from gen_fsm
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: init/1
|
||||
%% Returns: {ok, StateName, StateData} |
|
||||
%% {ok, StateName, StateData, Timeout} |
|
||||
%% ignore |
|
||||
%% {stop, StopReason}
|
||||
%%----------------------------------------------------------------------
|
||||
init([{SockMod, Socket}, Opts]) ->
|
||||
?INFO_MSG("started: ~p", [{SockMod, Socket}]),
|
||||
case SockMod of
|
||||
gen_tcp ->
|
||||
inet:setopts(Socket, [{packet, http}, {active, true}, {recbuf, 0}]);
|
||||
ssl ->
|
||||
ssl:setopts(Socket, [{packet, http}, {active, true}])
|
||||
end,
|
||||
{ok, wait_for_headers, #state{socket = Socket}}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: StateName/2
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
|
||||
wait_for_headers(_, StateData) ->
|
||||
{next_state, wait_for_headers, StateData}.
|
||||
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: StateName/3
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {reply, Reply, NextStateName, NextStateData} |
|
||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData} |
|
||||
%% {stop, Reason, Reply, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
%state_name(Event, From, StateData) ->
|
||||
% Reply = ok,
|
||||
% {reply, Reply, state_name, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_event/3
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
handle_event(_Event, StateName, StateData) ->
|
||||
{next_state, StateName, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_sync_event/4
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {reply, Reply, NextStateName, NextStateData} |
|
||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData} |
|
||||
%% {stop, Reason, Reply, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
handle_sync_event(_Event, _From, StateName, StateData) ->
|
||||
Reply = ok,
|
||||
{reply, Reply, StateName, StateData}.
|
||||
|
||||
code_change(_OldVsn, StateName, StateData, _Extra) ->
|
||||
{ok, StateName, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_info/3
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
handle_info({http_request, _Socket, Method, Path, _Version},
|
||||
StateName, StateData) ->
|
||||
{next_state, StateName, StateData#state{request_method = Method,
|
||||
request_path = Path}};
|
||||
handle_info({http_header, _Socket, _, 'Authorization', _, Auth},
|
||||
StateName, StateData) ->
|
||||
{next_state, StateName,
|
||||
StateData#state{request_auth = parse_auth(Auth)}};
|
||||
handle_info({http_eoh, _Socket}, StateName, StateData) ->
|
||||
process_request(StateData),
|
||||
{stop, normal, StateData};
|
||||
|
||||
handle_info({tcp_closed, _Socket}, StateName, StateData) ->
|
||||
{stop, normal, StateData};
|
||||
|
||||
handle_info({tcp_error, _Socket, _Reason}, StateName, StateData) ->
|
||||
{stop, normal, StateData};
|
||||
|
||||
handle_info(_, StateName, StateData) ->
|
||||
{next_state, StateName, StateData}.
|
||||
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: terminate/3
|
||||
%% Purpose: Shutdown the fsm
|
||||
%% Returns: any
|
||||
%%----------------------------------------------------------------------
|
||||
terminate(Reason, _StateName, StateData) ->
|
||||
?INFO_MSG("terminated: ~p", [Reason]),
|
||||
gen_tcp:close(StateData#state.socket),
|
||||
ok.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
send_text(State, Text) ->
|
||||
gen_tcp:send(State#state.socket, Text).
|
||||
|
||||
|
||||
process_request(#state{request_method = 'GET',
|
||||
request_path = {abs_path, Path},
|
||||
request_auth = undefined} = State) ->
|
||||
Out = make_xhtml_output(
|
||||
401,
|
||||
[{"WWW-Authenticate", "basic realm=\"ejabberd\""}],
|
||||
make_xhtml([{xmlelement, "h1", [],
|
||||
[{xmlcdata, "403 Unauthorized"}]}])),
|
||||
send_text(State, Out),
|
||||
ok;
|
||||
|
||||
process_request(#state{request_method = 'GET',
|
||||
request_path = {abs_path, Path},
|
||||
request_auth = {User, Pass}} = State) ->
|
||||
Out = make_xhtml_output(
|
||||
200,
|
||||
[],
|
||||
make_xhtml([{xmlelement, "h1", [],
|
||||
[{xmlcdata, "Welcome " ++ User}]}])),
|
||||
send_text(State, Out),
|
||||
ok;
|
||||
|
||||
process_request(State) ->
|
||||
todo.
|
||||
|
||||
|
||||
|
||||
make_xhtml(Els) ->
|
||||
{xmlelement, "html", [{"xmlns", "http://www.w3.org/1999/xhtml"},
|
||||
{"xml:lang", "en"},
|
||||
{"lang", "en"}],
|
||||
[{xmlelement, "head", [],
|
||||
[{xmlelement, "meta", [{"http-equiv", "Content-Type"},
|
||||
{"content", "text/html; charset=utf-8"}], []}]},
|
||||
{xmlelement, "body", [], Els}
|
||||
]}.
|
||||
|
||||
|
||||
make_xhtml_output(Status, Headers, XHTML) ->
|
||||
Data = list_to_binary([?XHTML_DOCTYPE, xml:element_to_string(XHTML)]),
|
||||
Headers1 = [{"Content-Type", "text/html; charset=utf-8"},
|
||||
{"Content-Length", integer_to_list(size(Data))} | Headers],
|
||||
H = lists:map(fun({Attr, Val}) ->
|
||||
[Attr, ": ", Val, "\r\n"]
|
||||
end, Headers1),
|
||||
SL = ["HTTP/1.1 ", integer_to_list(Status), " ",
|
||||
code_to_phrase(Status), "\r\n"],
|
||||
[SL, H, "\r\n", Data].
|
||||
|
||||
|
||||
|
||||
% Code below is taken (with some modifications) from the yaws webserver, which
|
||||
% is distributed under the folowing license:
|
||||
%
|
||||
%This software (the yaws webserver) is free software.
|
||||
%Parts of this software is Copyright (c) Claes Wikstrom <klacke@hyber.org>
|
||||
%Any use or misuse of the source code is hereby freely allowed.
|
||||
%
|
||||
%1. Redistributions of source code must retain the above copyright
|
||||
% notice as well as this list of conditions.
|
||||
%
|
||||
%2. Redistributions in binary form must reproduce the above copyright
|
||||
% notice as well as this list of conditions.
|
||||
|
||||
|
||||
%% url decode the path and return {Path, QueryPart}
|
||||
|
||||
url_decode_q_split(Path) ->
|
||||
url_decode_q_split(Path, []).
|
||||
|
||||
url_decode_q_split([$%, $C, $2, $%, Hi, Lo | Tail], Ack) ->
|
||||
Hex = hex_to_integer([Hi, Lo]),
|
||||
url_decode_q_split(Tail, [Hex|Ack]);
|
||||
url_decode_q_split([$%, $C, $3, $%, Hi, Lo | Tail], Ack) when Hi > $9 ->
|
||||
Hex = hex_to_integer([Hi+4, Lo]),
|
||||
url_decode_q_split(Tail, [Hex|Ack]);
|
||||
url_decode_q_split([$%, $C, $3, $%, Hi, Lo | Tail], Ack) when Hi < $A ->
|
||||
Hex = hex_to_integer([Hi+4+7, Lo]),
|
||||
url_decode_q_split(Tail, [Hex|Ack]);
|
||||
url_decode_q_split([$%, Hi, Lo | Tail], Ack) ->
|
||||
Hex = hex_to_integer([Hi, Lo]),
|
||||
url_decode_q_split(Tail, [Hex|Ack]);
|
||||
url_decode_q_split([$?|T], Ack) ->
|
||||
%% Don't decode the query string here, that is parsed separately.
|
||||
{path_norm_reverse(Ack), T};
|
||||
url_decode_q_split([H|T], Ack) ->
|
||||
url_decode_q_split(T, [H|Ack]);
|
||||
url_decode_q_split([], Ack) ->
|
||||
{path_norm_reverse(Ack), []}.
|
||||
|
||||
path_norm_reverse("/" ++ T) -> start_dir(0, "/", T);
|
||||
path_norm_reverse( T) -> start_dir(0, "", T).
|
||||
|
||||
start_dir(N, Path, ".." ) -> rest_dir(N, Path, "");
|
||||
start_dir(N, Path, "/" ++ T ) -> start_dir(N , Path, T);
|
||||
start_dir(N, Path, "./" ++ T ) -> start_dir(N , Path, T);
|
||||
start_dir(N, Path, "../" ++ T ) -> start_dir(N + 1, Path, T);
|
||||
start_dir(N, Path, T ) -> rest_dir (N , Path, T).
|
||||
|
||||
rest_dir (_N, Path, [] ) -> case Path of
|
||||
[] -> "/";
|
||||
_ -> Path
|
||||
end;
|
||||
rest_dir (0, Path, [ $/ | T ] ) -> start_dir(0 , [ $/ | Path ], T);
|
||||
rest_dir (N, Path, [ $/ | T ] ) -> start_dir(N - 1, Path , T);
|
||||
rest_dir (0, Path, [ H | T ] ) -> rest_dir (0 , [ H | Path ], T);
|
||||
rest_dir (N, Path, [ _H | T ] ) -> rest_dir (N , Path , T).
|
||||
|
||||
|
||||
%% hex_to_integer
|
||||
|
||||
|
||||
hex_to_integer(Hex) ->
|
||||
case catch erlang:list_to_integer(Hex, 16) of
|
||||
{'EXIT', _} ->
|
||||
old_hex_to_integer(Hex);
|
||||
X ->
|
||||
X
|
||||
end.
|
||||
|
||||
|
||||
old_hex_to_integer(Hex) ->
|
||||
DEHEX = fun (H) when H >= $a, H =< $f -> H - $a + 10;
|
||||
(H) when H >= $A, H =< $F -> H - $A + 10;
|
||||
(H) when H >= $0, H =< $9 -> H - $0
|
||||
end,
|
||||
lists:foldl(fun(E, Acc) -> Acc*16+DEHEX(E) end, 0, Hex).
|
||||
|
||||
code_to_phrase(100) -> "Continue";
|
||||
code_to_phrase(101) -> "Switching Protocols ";
|
||||
code_to_phrase(200) -> "OK";
|
||||
code_to_phrase(201) -> "Created";
|
||||
code_to_phrase(202) -> "Accepted";
|
||||
code_to_phrase(203) -> "Non-Authoritative Information";
|
||||
code_to_phrase(204) -> "No Content";
|
||||
code_to_phrase(205) -> "Reset Content";
|
||||
code_to_phrase(206) -> "Partial Content";
|
||||
code_to_phrase(300) -> "Multiple Choices";
|
||||
code_to_phrase(301) -> "Moved Permanently";
|
||||
code_to_phrase(302) -> "Found";
|
||||
code_to_phrase(303) -> "See Other";
|
||||
code_to_phrase(304) -> "Not Modified";
|
||||
code_to_phrase(305) -> "Use Proxy";
|
||||
code_to_phrase(306) -> "(Unused)";
|
||||
code_to_phrase(307) -> "Temporary Redirect";
|
||||
code_to_phrase(400) -> "Bad Request";
|
||||
code_to_phrase(401) -> "Unauthorized";
|
||||
code_to_phrase(402) -> "Payment Required";
|
||||
code_to_phrase(403) -> "Forbidden";
|
||||
code_to_phrase(404) -> "Not Found";
|
||||
code_to_phrase(405) -> "Method Not Allowed";
|
||||
code_to_phrase(406) -> "Not Acceptable";
|
||||
code_to_phrase(407) -> "Proxy Authentication Required";
|
||||
code_to_phrase(408) -> "Request Timeout";
|
||||
code_to_phrase(409) -> "Conflict";
|
||||
code_to_phrase(410) -> "Gone";
|
||||
code_to_phrase(411) -> "Length Required";
|
||||
code_to_phrase(412) -> "Precondition Failed";
|
||||
code_to_phrase(413) -> "Request Entity Too Large";
|
||||
code_to_phrase(414) -> "Request-URI Too Long";
|
||||
code_to_phrase(415) -> "Unsupported Media Type";
|
||||
code_to_phrase(416) -> "Requested Range Not Satisfiable";
|
||||
code_to_phrase(417) -> "Expectation Failed";
|
||||
code_to_phrase(500) -> "Internal Server Error";
|
||||
code_to_phrase(501) -> "Not Implemented";
|
||||
code_to_phrase(502) -> "Bad Gateway";
|
||||
code_to_phrase(503) -> "Service Unavailable";
|
||||
code_to_phrase(504) -> "Gateway Timeout";
|
||||
code_to_phrase(505) -> "HTTP Version Not Supported".
|
||||
|
||||
|
||||
parse_auth(Orig = "Basic " ++ Auth64) ->
|
||||
case decode_base64(Auth64) of
|
||||
{error, _Err} ->
|
||||
undefined;
|
||||
Auth ->
|
||||
case string:tokens(Auth, ":") of
|
||||
[User, Pass] ->
|
||||
{User, Pass};
|
||||
_ ->
|
||||
undefined
|
||||
end
|
||||
end;
|
||||
parse_auth(_) ->
|
||||
undefined.
|
||||
|
||||
|
||||
|
||||
decode_base64([]) ->
|
||||
[];
|
||||
decode_base64([Sextet1,Sextet2,$=,$=|Rest]) ->
|
||||
Bits2x6=
|
||||
(d(Sextet1) bsl 18) bor
|
||||
(d(Sextet2) bsl 12),
|
||||
Octet1=Bits2x6 bsr 16,
|
||||
[Octet1|decode_base64(Rest)];
|
||||
decode_base64([Sextet1,Sextet2,Sextet3,$=|Rest]) ->
|
||||
Bits3x6=
|
||||
(d(Sextet1) bsl 18) bor
|
||||
(d(Sextet2) bsl 12) bor
|
||||
(d(Sextet3) bsl 6),
|
||||
Octet1=Bits3x6 bsr 16,
|
||||
Octet2=(Bits3x6 bsr 8) band 16#ff,
|
||||
[Octet1,Octet2|decode_base64(Rest)];
|
||||
decode_base64([Sextet1,Sextet2,Sextet3,Sextet4|Rest]) ->
|
||||
Bits4x6=
|
||||
(d(Sextet1) bsl 18) bor
|
||||
(d(Sextet2) bsl 12) bor
|
||||
(d(Sextet3) bsl 6) bor
|
||||
d(Sextet4),
|
||||
Octet1=Bits4x6 bsr 16,
|
||||
Octet2=(Bits4x6 bsr 8) band 16#ff,
|
||||
Octet3=Bits4x6 band 16#ff,
|
||||
[Octet1,Octet2,Octet3|decode_base64(Rest)];
|
||||
decode_base64(_CatchAll) ->
|
||||
{error, bad_base64}.
|
||||
|
||||
d(X) when X >= $A, X =<$Z ->
|
||||
X-65;
|
||||
d(X) when X >= $a, X =<$z ->
|
||||
X-71;
|
||||
d(X) when X >= $0, X =<$9 ->
|
||||
X+4;
|
||||
d($+) -> 62;
|
||||
d($/) -> 63;
|
||||
d(_) -> 63.
|
||||
|
@ -1,328 +0,0 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% File : ejabberd_wcs.erl
|
||||
%%% Author : Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Purpose : Web Client Service
|
||||
%%% Created : 13 Jul 2004 by Alexey Shchepin <alexey@sevcom.net>
|
||||
%%% Id : $Id$
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
-module(ejabberd_wcs).
|
||||
-author('alexey@sevcom.net').
|
||||
-vsn('$Revision$ ').
|
||||
|
||||
-behaviour(gen_fsm).
|
||||
|
||||
%% External exports
|
||||
-export([start_link/2,
|
||||
init/1,
|
||||
handle_event/3,
|
||||
handle_sync_event/4,
|
||||
code_change/4,
|
||||
handle_info/3,
|
||||
terminate/3,
|
||||
send/2,
|
||||
recv/3,
|
||||
close/1,
|
||||
process_request/1]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
-include("ejabberd_http.hrl").
|
||||
|
||||
-record(http_poll, {id, pid}).
|
||||
|
||||
-record(state, {id,
|
||||
key,
|
||||
output = "",
|
||||
input = "",
|
||||
waiting_input = false,
|
||||
timer}).
|
||||
|
||||
%-define(DBGFSM, true).
|
||||
|
||||
-ifdef(DBGFSM).
|
||||
-define(FSMOPTS, [{debug, [trace]}]).
|
||||
-else.
|
||||
-define(FSMOPTS, []).
|
||||
-endif.
|
||||
|
||||
-define(HTTP_POLL_TIMEOUT, 300000).
|
||||
-define(CT, {"Content-Type", "text/xml; charset=utf-8"}).
|
||||
-define(BAD_REQUEST, [?CT, {"Set-Cookie", "ID=-3:0; expires=-1"}]).
|
||||
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% API
|
||||
%%%----------------------------------------------------------------------
|
||||
start(ID, Key) ->
|
||||
mnesia:create_table(http_poll,
|
||||
[{ram_copies, [node()]},
|
||||
{attributes, record_info(fields, http_poll)}]),
|
||||
supervisor:start_child(ejabberd_http_poll_sup, [ID, Key]).
|
||||
|
||||
start_link(ID, Key) ->
|
||||
gen_fsm:start_link(?MODULE, [ID, Key], ?FSMOPTS).
|
||||
|
||||
send({http_poll, FsmRef}, Packet) ->
|
||||
gen_fsm:sync_send_all_state_event(FsmRef, {send, Packet}).
|
||||
|
||||
recv({http_poll, FsmRef}, _Length, Timeout) ->
|
||||
gen_fsm:sync_send_all_state_event(FsmRef, recv, Timeout).
|
||||
|
||||
close({http_poll, FsmRef}) ->
|
||||
catch gen_fsm:sync_send_all_state_event(FsmRef, close).
|
||||
|
||||
|
||||
process_request(#request{path = [],
|
||||
data = Data} = Request) ->
|
||||
case catch parse_request(Data) of
|
||||
{ok, ID1, Key, NewKey, Packet} ->
|
||||
ID = if
|
||||
(ID1 == "0") or (ID1 == "mobile") ->
|
||||
NewID = sha:sha(term_to_binary({now(), make_ref()})),
|
||||
{ok, Pid} = start(NewID, ""),
|
||||
mnesia:transaction(
|
||||
fun() ->
|
||||
mnesia:write(#http_poll{id = NewID,
|
||||
pid = Pid})
|
||||
end),
|
||||
NewID;
|
||||
true ->
|
||||
ID1
|
||||
end,
|
||||
case http_put(ID, Key, NewKey, Packet) of
|
||||
{error, not_exists} ->
|
||||
{200, ?BAD_REQUEST, ""};
|
||||
{error, bad_key} ->
|
||||
{200, ?BAD_REQUEST, ""};
|
||||
ok ->
|
||||
receive
|
||||
after 100 -> ok
|
||||
end,
|
||||
case http_get(ID) of
|
||||
{error, not_exists} ->
|
||||
{200, [?BAD_REQUEST], ""};
|
||||
{ok, OutPacket} ->
|
||||
if
|
||||
ID == ID1 ->
|
||||
{200, [?CT], OutPacket};
|
||||
ID1 == "mobile" ->
|
||||
{200, [?CT], [ID, $\n, OutPacket]};
|
||||
true ->
|
||||
Cookie = "ID=" ++ ID ++ "; expires=-1",
|
||||
{200, [?CT, {"Set-Cookie", Cookie}],
|
||||
OutPacket}
|
||||
end
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
{200, [?CT, {"Set-Cookie", "ID=-2:0; expires=-1"}], ""}
|
||||
end.
|
||||
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Callback functions from gen_fsm
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: init/1
|
||||
%% Returns: {ok, StateName, StateData} |
|
||||
%% {ok, StateName, StateData, Timeout} |
|
||||
%% ignore |
|
||||
%% {stop, StopReason}
|
||||
%%----------------------------------------------------------------------
|
||||
init([ID, Key]) ->
|
||||
?INFO_MSG("started: ~p", [{ID, Key}]),
|
||||
Opts = [], % TODO
|
||||
ejabberd_c2s:start({?MODULE, {http_poll, self()}}, Opts),
|
||||
Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []),
|
||||
{ok, loop, #state{id = ID,
|
||||
key = Key,
|
||||
timer = Timer}}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: StateName/2
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: StateName/3
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {reply, Reply, NextStateName, NextStateData} |
|
||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData} |
|
||||
%% {stop, Reason, Reply, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
%state_name(Event, From, StateData) ->
|
||||
% Reply = ok,
|
||||
% {reply, Reply, state_name, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_event/3
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
handle_event(Event, StateName, StateData) ->
|
||||
{next_state, StateName, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_sync_event/4
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {reply, Reply, NextStateName, NextStateData} |
|
||||
%% {reply, Reply, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData} |
|
||||
%% {stop, Reason, Reply, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
handle_sync_event({send, Packet}, From, StateName, StateData) ->
|
||||
Output = [StateData#state.output | Packet],
|
||||
Reply = ok,
|
||||
{reply, Reply, StateName, StateData#state{output = Output}};
|
||||
|
||||
handle_sync_event(recv, From, StateName, StateData) ->
|
||||
case StateData#state.input of
|
||||
"" ->
|
||||
{next_state, StateName, StateData#state{waiting_input = From}};
|
||||
Input ->
|
||||
Reply = {ok, list_to_binary(Input)},
|
||||
{reply, Reply, StateName, StateData#state{input = "",
|
||||
waiting_input = false}}
|
||||
end;
|
||||
|
||||
handle_sync_event(stop, From, StateName, StateData) ->
|
||||
Reply = ok,
|
||||
{stop, normal, Reply, StateData};
|
||||
|
||||
handle_sync_event({http_put, Key, NewKey, Packet},
|
||||
From, StateName, StateData) ->
|
||||
Allow = case StateData#state.key of
|
||||
"" ->
|
||||
true;
|
||||
OldKey ->
|
||||
NextKey = jlib:encode_base64(
|
||||
binary_to_list(crypto:sha(Key))),
|
||||
if
|
||||
OldKey == NextKey ->
|
||||
true;
|
||||
true ->
|
||||
false
|
||||
end
|
||||
end,
|
||||
if
|
||||
Allow ->
|
||||
case StateData#state.waiting_input of
|
||||
false ->
|
||||
Input = [StateData#state.input | Packet],
|
||||
Reply = ok,
|
||||
{reply, Reply, StateName, StateData#state{input = Input,
|
||||
key = NewKey}};
|
||||
Receiver ->
|
||||
gen_fsm:reply(Receiver, {ok, list_to_binary(Packet)}),
|
||||
cancel_timer(StateData#state.timer),
|
||||
Timer = erlang:start_timer(?HTTP_POLL_TIMEOUT, self(), []),
|
||||
Reply = ok,
|
||||
{reply, Reply, StateName,
|
||||
StateData#state{waiting_input = false,
|
||||
key = NewKey,
|
||||
timer = Timer}}
|
||||
end;
|
||||
true ->
|
||||
Reply = {error, bad_key},
|
||||
{reply, Reply, StateName, StateData}
|
||||
end;
|
||||
|
||||
handle_sync_event(http_get, From, StateName, StateData) ->
|
||||
Reply = {ok, StateData#state.output},
|
||||
{reply, Reply, StateName, StateData#state{output = ""}};
|
||||
|
||||
handle_sync_event(Event, From, StateName, StateData) ->
|
||||
Reply = ok,
|
||||
{reply, Reply, StateName, StateData}.
|
||||
|
||||
code_change(OldVsn, StateName, StateData, Extra) ->
|
||||
{ok, StateName, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: handle_info/3
|
||||
%% Returns: {next_state, NextStateName, NextStateData} |
|
||||
%% {next_state, NextStateName, NextStateData, Timeout} |
|
||||
%% {stop, Reason, NewStateData}
|
||||
%%----------------------------------------------------------------------
|
||||
handle_info({timeout, Timer, _}, StateName,
|
||||
#state{timer = Timer} = StateData) ->
|
||||
{stop, normal, StateData};
|
||||
|
||||
handle_info(_, StateName, StateData) ->
|
||||
{next_state, StateName, StateData}.
|
||||
|
||||
%%----------------------------------------------------------------------
|
||||
%% Func: terminate/3
|
||||
%% Purpose: Shutdown the fsm
|
||||
%% Returns: any
|
||||
%%----------------------------------------------------------------------
|
||||
terminate(Reason, StateName, StateData) ->
|
||||
mnesia:transaction(
|
||||
fun() ->
|
||||
mnesia:delete({http_poll, StateData#state.id})
|
||||
end),
|
||||
case StateData#state.waiting_input of
|
||||
false ->
|
||||
ok;
|
||||
Receiver ->
|
||||
gen_fsm:reply(Receiver, {error, closed})
|
||||
end,
|
||||
ok.
|
||||
|
||||
%%%----------------------------------------------------------------------
|
||||
%%% Internal functions
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
|
||||
http_put(ID, Key, NewKey, Packet) ->
|
||||
case mnesia:dirty_read({http_poll, ID}) of
|
||||
[] ->
|
||||
{error, not_exists};
|
||||
[#http_poll{pid = FsmRef}] ->
|
||||
gen_fsm:sync_send_all_state_event(
|
||||
FsmRef, {http_put, Key, NewKey, Packet})
|
||||
end.
|
||||
|
||||
http_get(ID) ->
|
||||
case mnesia:dirty_read({http_poll, ID}) of
|
||||
[] ->
|
||||
{error, not_exists};
|
||||
[#http_poll{pid = FsmRef}] ->
|
||||
gen_fsm:sync_send_all_state_event(FsmRef, http_get)
|
||||
end.
|
||||
|
||||
|
||||
parse_request(Data) ->
|
||||
Comma = string:chr(Data, $,),
|
||||
Header = lists:sublist(Data, Comma - 1),
|
||||
Packet = lists:nthtail(Comma, Data),
|
||||
{ID, Key, NewKey} =
|
||||
case string:tokens(Header, ";") of
|
||||
[ID1] ->
|
||||
{ID1, "", ""};
|
||||
[ID1, Key1] ->
|
||||
{ID1, Key1, Key1};
|
||||
[ID1, Key1, NewKey1] ->
|
||||
{ID1, Key1, NewKey1}
|
||||
end,
|
||||
{ok, ID, Key, NewKey, Packet}.
|
||||
|
||||
|
||||
cancel_timer(Timer) ->
|
||||
erlang:cancel_timer(Timer),
|
||||
receive
|
||||
{timeout, Timer, _} ->
|
||||
ok
|
||||
after 0 ->
|
||||
ok
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user