+2004-12-05 Alexey Shchepin <alexey@sevcom.net>
+
+ * src/web/ejabberd_web_admin.erl: Changed type of password field
+ to "password"
+
+ * src/jlib.hrl: More stream error defines (thanks to Sergei
+ Golovan)
+
+ * src/ejabberd_c2s.erl: Support for starttls_required option
+ (thanks to Sergei Golovan)
+
+ * src/mod_muc/mod_muc_room.erl: Fixed mistake in case condition
+ (thanks to Sergei Golovan)
+
+ * src/xml_stream.erl: Added function parse_element/1
+
+ * src/expat_erl.c: Added PARSE_FINAL_COMMAND
+
2004-12-03 Alexey Shchepin <alexey@sevcom.net>
* src/ejabberd_listener.erl: Enable keepalive option
access,
shaper,
tls = false,
+ tls_required = false,
tls_enabled = false,
tls_options = [],
authentificated = false,
xml:element_to_string(?SERR_INVALID_NAMESPACE)).
-define(INVALID_XML_ERR,
xml:element_to_string(?SERR_XML_NOT_WELL_FORMED)).
+-define(POLICY_VIOLATION_ERR(Lang, Text),
+ xml:element_to_string(?SERRT_POLICY_VIOLATION(Lang, Text))).
%%%----------------------------------------------------------------------
%%% API
_ -> none
end,
StartTLS = lists:member(starttls, Opts),
+ StartTLSRequired = lists:member(starttls_required, Opts),
TLSEnabled = lists:member(tls, Opts),
- TLS = StartTLS orelse TLSEnabled,
+ TLS = StartTLS orelse StartTLSRequired orelse TLSEnabled,
TLSOpts = lists:filter(fun({certfile, _}) -> true;
(_) -> false
end, Opts),
RecPid = ejabberd_receiver:start(Socket, SockMod, none),
{SockMod, Socket, RecPid}
end,
- {ok, wait_for_stream, #state{socket = Socket1,
- sockmod = SockMod1,
- receiver = ReceiverPid,
- tls = TLS,
- tls_enabled = TLSEnabled,
- tls_options = TLSOpts,
- streamid = new_id(),
- access = Access,
- shaper = Shaper}}.
+ {ok, wait_for_stream, #state{socket = Socket1,
+ sockmod = SockMod1,
+ receiver = ReceiverPid,
+ tls = TLS,
+ tls_required = StartTLSRequired,
+ tls_enabled = TLSEnabled,
+ tls_options = TLSOpts,
+ streamid = new_id(),
+ access = Access,
+ shaper = Shaper}}.
%%----------------------------------------------------------------------
end, cyrsasl:listmech()),
TLS = StateData#state.tls,
TLSEnabled = StateData#state.tls_enabled,
+ TLSRequired = StateData#state.tls_required,
SockMod = StateData#state.sockmod,
TLSFeature =
case (TLS == true) andalso
(TLSEnabled == false) andalso
(SockMod == gen_tcp) of
true ->
- [{xmlelement, "starttls",
- [{"xmlns", ?NS_TLS}], []}];
+ case TLSRequired of
+ true ->
+ [{xmlelement, "starttls",
+ [{"xmlns", ?NS_TLS}],
+ [{xmlelement, "required",
+ [], []}]}];
+ _ ->
+ [{xmlelement, "starttls",
+ [{"xmlns", ?NS_TLS}], []}]
+ end;
false ->
[]
end,
{xmlelement, Name, Attrs, Els} = El,
TLS = StateData#state.tls,
TLSEnabled = StateData#state.tls_enabled,
+ TLSRequired = StateData#state.tls_required,
SockMod = StateData#state.sockmod,
case {xml:get_attr_s("xmlns", Attrs), Name} of
- {?NS_SASL, "auth"} ->
+ {?NS_SASL, "auth"} when not ((SockMod == gen_tcp) and TLSRequired) ->
Mech = xml:get_attr_s("mechanism", Attrs),
ClientIn = jlib:decode_base64(xml:get_cdata(Els)),
case cyrsasl:server_start(StateData#state.sasl_state,
tls_enabled = true
}};
_ ->
- case jlib:iq_query_info(El) of
- #iq{xmlns = ?NS_REGISTER} = IQ ->
- ResIQ = mod_register:process_iq(
- {"", "", ""}, {"", ?MYNAME, ""}, IQ),
- Res1 = jlib:replace_from_to({"", ?MYNAME, ""},
- {"", "", ""},
- jlib:iq_to_xml(ResIQ)),
- Res = jlib:remove_attr("to", Res1),
- send_element(StateData, Res),
- {next_state, wait_for_feature_request, StateData};
- _ ->
- {next_state, wait_for_feature_request, StateData}
+ if
+ (SockMod == gen_tcp) and TLSRequired ->
+ Lang = StateData#state.lang,
+ send_text(StateData, ?POLICY_VIOLATION_ERR(
+ Lang,
+ "Use of STARTTLS required") ++
+ ?STREAM_TRAILER),
+ {stop, normal, StateData};
+ true ->
+ case jlib:iq_query_info(El) of
+ #iq{xmlns = ?NS_REGISTER} = IQ ->
+ ResIQ = mod_register:process_iq(
+ {"", "", ""}, {"", ?MYNAME, ""}, IQ),
+ Res1 = jlib:replace_from_to({"", ?MYNAME, ""},
+ {"", "", ""},
+ jlib:iq_to_xml(ResIQ)),
+ Res = jlib:remove_attr("to", Res1),
+ send_element(StateData, Res),
+ {next_state, wait_for_feature_request, StateData};
+ _ ->
+ {next_state, wait_for_feature_request, StateData}
+ end
end
end;
#define XML_ERROR 3
#define PARSE_COMMAND 0
+#define PARSE_FINAL_COMMAND 1
ei_x_buff event_buf;
switch (command)
{
case PARSE_COMMAND:
+ case PARSE_FINAL_COMMAND:
ei_x_new_with_version(&event_buf);
- res = XML_Parse(d->parser, buf, len, 0);
+ res = XML_Parse(d->parser, buf, len, command == PARSE_FINAL_COMMAND);
if(!res)
{
%-define(SERR_,
% ?STREAM_ERROR("")).
+-define(STREAM_ERRORT(Condition, Lang, Text),
+ {xmlelement, "stream:error",
+ [],
+ [{xmlelement, Condition, [{"xmlns", ?NS_STREAMS}], []},
+ {xmlelement, "text", [{"xml:lang", Lang}, {"xmlns", ?NS_STREAMS}],
+ [{xmlcdata, translate:translate(Lang, Text)}]}]}).
+
+-define(SERRT_BAD_FORMAT(Lang, Text),
+ ?STREAM_ERRORT("bad-format", Lang, Text)).
+-define(SERRT_BAD_NAMESPACE_PREFIX(Lang, Text),
+ ?STREAM_ERRORT("bad-namespace-prefix", Lang, Text)).
+-define(SERRT_CONFLICT(Lang, Text),
+ ?STREAM_ERRORT("conflict", Lang, Text)).
+-define(SERRT_CONNECTION_TIMEOUT(Lang, Text),
+ ?STREAM_ERRORT("connection-timeout", Lang, Text)).
+-define(SERRT_HOST_GONE(Lang, Text),
+ ?STREAM_ERRORT("host-gone", Lang, Text)).
+-define(SERRT_HOST_UNKNOWN(Lang, Text),
+ ?STREAM_ERRORT("host-unknown", Lang, Text)).
+-define(SERRT_IMPROPER_ADDRESSING(Lang, Text),
+ ?STREAM_ERRORT("improper-addressing", Lang, Text)).
+-define(SERRT_INTERNAL_SERVER_ERROR(Lang, Text),
+ ?STREAM_ERRORT("internal-server-error", Lang, Text)).
+-define(SERRT_INVALID_FROM(Lang, Text),
+ ?STREAM_ERRORT("invalid-from", Lang, Text)).
+-define(SERRT_INVALID_ID(Lang, Text),
+ ?STREAM_ERRORT("invalid-id", Lang, Text)).
+-define(SERRT_INVALID_NAMESPACE(Lang, Text),
+ ?STREAM_ERRORT("invalid-namespace", Lang, Text)).
+-define(SERRT_INVALID_XML(Lang, Text),
+ ?STREAM_ERRORT("invalid-xml", Lang, Text)).
+-define(SERRT_NOT_AUTHORIZED(Lang, Text),
+ ?STREAM_ERRORT("not-authorized", Lang, Text)).
+-define(SERRT_POLICY_VIOLATION(Lang, Text),
+ ?STREAM_ERRORT("policy-violation", Lang, Text)).
+-define(SERRT_REMOTE_CONNECTION_FAILED(Lang, Text),
+ ?STREAM_ERRORT("remote-connection-failed", Lang, Text)).
+-define(SERRT_RESOURSE_CONSTRAINT(Lang, Text),
+ ?STREAM_ERRORT("resource-constraint", Lang, Text)).
+-define(SERRT_RESTRICTED_XML(Lang, Text),
+ ?STREAM_ERRORT("restricted-xml", Lang, Text)).
+% TODO: include hostname or IP
+-define(SERRT_SEE_OTHER_HOST(Lang, Text),
+ ?STREAM_ERRORT("see-other-host", Lang, Text)).
+-define(SERRT_SYSTEM_SHUTDOWN(Lang, Text),
+ ?STREAM_ERRORT("system-shutdown", Lang, Text)).
+-define(SERRT_UNSUPPORTED_ENCODING(Lang, Text),
+ ?STREAM_ERRORT("unsupported-encoding", Lang, Text)).
+-define(SERRT_UNSUPPORTED_STANZA_TYPE(Lang, Text),
+ ?STREAM_ERRORT("unsupported-stanza-type", Lang, Text)).
+-define(SERRT_UNSUPPORTED_VERSION(Lang, Text),
+ ?STREAM_ERRORT("unsupported-version", Lang, Text)).
+-define(SERRT_XML_NOT_WELL_FORMED(Lang, Text),
+ ?STREAM_ERRORT("xml-not-well-formed", Lang, Text)).
+%-define(SERRT_(Lang, Text),
+% ?STREAM_ERRORT("", Lang, Text)).
+
-record(jid, {user, server, resource,
luser, lserver, lresource}).
_ ->
count_maxchars_shift(Nick, MaxChars, HL)
end,
-
lists:max([Shift0, Shift1, Shift2, Shift3]).
count_seconds_shift(Seconds, HistoryList) ->
end;
_ ->
case catch list_to_integer(AttrVal) of
- IntVal when is_integer(IntVal) and IntVal >= 0 ->
+ IntVal when is_integer(IntVal) and (IntVal >= 0) ->
IntVal;
_ ->
false
JID, outcast,
set_role(JID, none, SD));
{JID, affiliation, A, Reason} when
- (A == admin) or (A == owner)->
+ (A == admin) or (A == owner) ->
SD1 = set_affiliation(JID, A, SD),
SD2 = set_role(JID, moderator, SD1),
send_update_presence(JID, SD2),
end, lists:sort(Resources)))]
end,
Password = ejabberd_auth:get_password_s(User),
- FPassword = [?INPUT("text", "password", Password), ?C(" "),
+ FPassword = [?INPUT("password", "password", Password), ?C(" "),
?INPUTT("submit", "chpassword", "Change Password")],
QueueLen = length(mnesia:dirty_read({offline_msg, User})),
FQueueLen = [?AC("queue/",
send_text/2,
new/1,
parse/2,
- close/1]).
+ close/1,
+ parse_element/1]).
-define(XML_START, 0).
-define(XML_END, 1).
-define(XML_ERROR, 3).
-define(PARSE_COMMAND, 0).
+-define(PARSE_FINAL_COMMAND, 1).
-record(xml_stream_state, {callback_pid, port, stack}).
close(#xml_stream_state{port = Port}) ->
port_close(Port).
+
+
+parse_element(Str) ->
+ Port = open_port({spawn, expat_erl}, [binary]),
+ Res = port_control(Port, ?PARSE_FINAL_COMMAND, Str),
+ port_close(Port),
+ process_element_events(binary_to_term(Res)).
+
+process_element_events(Events) ->
+ process_element_events(Events, []).
+
+process_element_events([], _Stack) ->
+ {error, parse_error};
+process_element_events([Event | Events], Stack) ->
+ case Event of
+ {?XML_START, {Name, Attrs}} ->
+ process_element_events(
+ Events, [{xmlelement, Name, Attrs, []} | Stack]);
+ {?XML_END, _EndName} ->
+ case Stack of
+ [{xmlelement, Name, Attrs, Els} | Tail] ->
+ NewEl = {xmlelement, Name, Attrs, lists:reverse(Els)},
+ case Tail of
+ [] ->
+ if
+ Events == [] ->
+ NewEl;
+ true ->
+ {error, parse_error}
+ end;
+ [{xmlelement, Name1, Attrs1, Els1} | Tail1] ->
+ process_element_events(
+ Events,
+ [{xmlelement, Name1, Attrs1, [NewEl | Els1]} |
+ Tail1])
+ end
+ end;
+ {?XML_CDATA, CData} ->
+ case Stack of
+ [{xmlelement, Name, Attrs, Els} | Tail] ->
+ process_element_events(
+ Events,
+ [{xmlelement, Name, Attrs, [{xmlcdata, CData} | Els]} |
+ Tail]);
+ [] ->
+ process_element_events(Events, [])
+ end;
+ {?XML_ERROR, Err} ->
+ {error, Err}
+ end.
+