mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-28 16:34:13 +01:00
* src/mod_muc/mod_muc_room.erl: Support for history management
(thanks to Sergei Golovan) * src/mod_stats.erl: Updated error codes (thanks to Sergei Golovan) * src/mod_irc/mod_irc.erl: Likewise * src/mod_configure.erl: "jabber:iq:data" replaced with "ejabber:config" namespace (thanks to Sergei Golovan) * src/mod_disco.erl: Likewise SVN Revision: 204
This commit is contained in:
parent
35bfd03669
commit
fdf25720e0
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
2004-02-15 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/mod_muc/mod_muc_room.erl: Support for history management
|
||||
(thanks to Sergei Golovan)
|
||||
|
||||
* src/mod_stats.erl: Updated error codes (thanks to Sergei
|
||||
Golovan)
|
||||
* src/mod_irc/mod_irc.erl: Likewise
|
||||
|
||||
* src/mod_configure.erl: "jabber:iq:data" replaced with
|
||||
"ejabber:config" namespace (thanks to Sergei Golovan)
|
||||
* src/mod_disco.erl: Likewise
|
||||
|
||||
2004-02-12 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/ejabberd_c2s.erl: Added <session/> to stream features
|
||||
|
@ -23,15 +23,15 @@
|
||||
|
||||
start(Opts) ->
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_IQDATA,
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_EJABBERD_CONFIG,
|
||||
?MODULE, process_local_iq, IQDisc),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_IQDATA,
|
||||
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_EJABBERD_CONFIG,
|
||||
?MODULE, process_sm_iq, IQDisc),
|
||||
ok.
|
||||
|
||||
stop() ->
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_IQDATA),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_IQDATA).
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_EJABBERD_CONFIG),
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_EJABBERD_CONFIG).
|
||||
|
||||
|
||||
process_local_iq(From, _To, #iq{id = ID, type = Type,
|
||||
@ -43,13 +43,18 @@ process_local_iq(From, _To, #iq{id = ID, type = Type,
|
||||
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
|
||||
case Type of
|
||||
set ->
|
||||
case xml:get_tag_attr_s("type", SubEl) of
|
||||
XDataEl = find_xdata_el(SubEl),
|
||||
case XDataEl of
|
||||
false ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]};
|
||||
{xmlelement, _Name, Attrs, SubEls} ->
|
||||
case xml:get_attr_s("type", Attrs) of
|
||||
"cancel" ->
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS}], []}]};
|
||||
"submit" ->
|
||||
XData = jlib:parse_xdata_submit(SubEl),
|
||||
XData = jlib:parse_xdata_submit(XDataEl),
|
||||
case XData of
|
||||
invalid ->
|
||||
IQ#iq{type = error,
|
||||
@ -74,7 +79,8 @@ process_local_iq(From, _To, #iq{id = ID, type = Type,
|
||||
end;
|
||||
_ ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]}
|
||||
end
|
||||
end;
|
||||
get ->
|
||||
Node =
|
||||
@ -137,7 +143,8 @@ get_form(["running nodes", ENode, "DB"], Lang) ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
Tables ->
|
||||
STables = lists:sort(Tables),
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "DB Tables Configuration")}]},
|
||||
@ -157,7 +164,7 @@ get_form(["running nodes", ENode, "DB"], Lang) ->
|
||||
?TABLEFIELD(Table, Type)
|
||||
end
|
||||
end, STables)
|
||||
]}
|
||||
]}]}
|
||||
end
|
||||
end;
|
||||
|
||||
@ -171,7 +178,8 @@ get_form(["running nodes", ENode, "modules", "stop"], Lang) ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR};
|
||||
Modules ->
|
||||
SModules = lists:sort(Modules),
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Stop Modules")}]},
|
||||
@ -183,12 +191,13 @@ get_form(["running nodes", ENode, "modules", "stop"], Lang) ->
|
||||
S = atom_to_list(M),
|
||||
?XFIELD("boolean", S, S, "0")
|
||||
end, SModules)
|
||||
]}
|
||||
]}]}
|
||||
end
|
||||
end;
|
||||
|
||||
get_form(["running nodes", ENode, "modules", "start"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Start Modules")}]},
|
||||
@ -203,10 +212,11 @@ get_form(["running nodes", ENode, "modules", "start"], Lang) ->
|
||||
{"var", "modules"}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, "[]."}]}]
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["running nodes", ENode, "backup", "backup"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Backup to File")}]},
|
||||
@ -221,10 +231,11 @@ get_form(["running nodes", ENode, "backup", "backup"], Lang) ->
|
||||
{"var", "path"}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, ""}]}]
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["running nodes", ENode, "backup", "restore"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Restore Backup from File")}]},
|
||||
@ -239,10 +250,11 @@ get_form(["running nodes", ENode, "backup", "restore"], Lang) ->
|
||||
{"var", "path"}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, ""}]}]
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["running nodes", ENode, "backup", "textfile"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Dump Backup to Text File")}]},
|
||||
@ -257,10 +269,11 @@ get_form(["running nodes", ENode, "backup", "textfile"], Lang) ->
|
||||
{"var", "path"}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, ""}]}]
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["running nodes", ENode, "import", "file"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Import User from File")}]},
|
||||
@ -275,10 +288,11 @@ get_form(["running nodes", ENode, "import", "file"], Lang) ->
|
||||
{"var", "path"}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, ""}]}]
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["running nodes", ENode, "import", "dir"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Import User from Dir")}]},
|
||||
@ -293,10 +307,11 @@ get_form(["running nodes", ENode, "import", "dir"], Lang) ->
|
||||
{"var", "path"}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, ""}]}]
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["config", "hostname"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Hostname Configuration")}]},
|
||||
@ -309,10 +324,11 @@ get_form(["config", "hostname"], Lang) ->
|
||||
translate:translate(Lang, "Host name")},
|
||||
{"var", "hostname"}],
|
||||
[{xmlelement, "value", [], [{xmlcdata, ?MYNAME}]}]}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["config", "acls"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "ACLs Configuration")}]},
|
||||
@ -332,10 +348,11 @@ get_form(["config", "acls"], Lang) ->
|
||||
[ets:tab2list(acl)])),
|
||||
"\n"))
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["config", "access"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Access Configuration")}]},
|
||||
@ -362,10 +379,11 @@ get_form(["config", "access"], Lang) ->
|
||||
])),
|
||||
"\n"))
|
||||
}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_form(["config", "remusers"], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Remove Users")}]},
|
||||
@ -381,7 +399,7 @@ get_form(["config", "remusers"], Lang) ->
|
||||
?XFIELD("boolean", U, U, "0")
|
||||
end, lists:sort(Users))
|
||||
end
|
||||
};
|
||||
}]};
|
||||
|
||||
get_form(_, Lang) ->
|
||||
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
||||
@ -712,13 +730,18 @@ process_sm_iq(From, To,
|
||||
Lang = xml:get_tag_attr_s("xml:lang", SubEl),
|
||||
case Type of
|
||||
set ->
|
||||
case xml:get_tag_attr_s("type", SubEl) of
|
||||
XDataEl = find_xdata_el(SubEl),
|
||||
case XDataEl of
|
||||
false ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ACCEPTABLE]};
|
||||
{xmlelement, _Name, Attrs, SubEls} ->
|
||||
case xml:get_attr_s("type", Attrs) of
|
||||
"cancel" ->
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS}], []}]};
|
||||
"submit" ->
|
||||
XData = jlib:parse_xdata_submit(SubEl),
|
||||
XData = jlib:parse_xdata_submit(XDataEl),
|
||||
case XData of
|
||||
invalid ->
|
||||
IQ#iq{type = error,
|
||||
@ -744,7 +767,8 @@ process_sm_iq(From, To,
|
||||
end;
|
||||
_ ->
|
||||
IQ#iq{type = error,
|
||||
sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
|
||||
sub_el = [SubEl, ?ERR_BAD_REQUEST]}
|
||||
end
|
||||
end;
|
||||
get ->
|
||||
Node =
|
||||
@ -764,7 +788,8 @@ process_sm_iq(From, To,
|
||||
|
||||
|
||||
get_sm_form(User, [], Lang) ->
|
||||
{result, [{xmlelement, "title", [],
|
||||
{result, [{xmlelement, "x", [{"xmlns", ?NS_XDATA}],
|
||||
[{xmlelement, "title", [],
|
||||
[{xmlcdata,
|
||||
translate:translate(
|
||||
Lang, "Administration of " ++ User)}]},
|
||||
@ -791,7 +816,7 @@ get_sm_form(User, [], Lang) ->
|
||||
% translate:translate(Lang, "Host name")},
|
||||
% {"var", "hostname"}],
|
||||
% [{xmlelement, "value", [], [{xmlcdata, ?MYNAME}]}]}
|
||||
]};
|
||||
]}]};
|
||||
|
||||
get_sm_form(_, _, Lang) ->
|
||||
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
||||
@ -820,3 +845,20 @@ set_sm_form(User, [], Lang, XData) ->
|
||||
end;
|
||||
set_sm_form(_, _, Lang, XData) ->
|
||||
{error, ?ERR_SERVICE_UNAVAILABLE}.
|
||||
|
||||
find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
|
||||
find_xdata_el1(SubEls).
|
||||
|
||||
find_xdata_el1([]) ->
|
||||
false;
|
||||
|
||||
find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) ->
|
||||
case xml:get_attr_s("xmlns", Attrs) of
|
||||
?NS_XDATA ->
|
||||
{xmlelement, Name, Attrs, SubEls};
|
||||
_ ->
|
||||
find_xdata_el1(Els)
|
||||
end;
|
||||
|
||||
find_xdata_el1([_ | Els]) ->
|
||||
find_xdata_el1(Els).
|
||||
|
@ -157,7 +157,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
|
||||
"query",
|
||||
[{"xmlns", XMLNS},
|
||||
{"node", SNode}],
|
||||
[feature_to_xml({?NS_IQDATA})]}]};
|
||||
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]};
|
||||
{allow, ["running nodes", ENode, "modules"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes", ENode, "modules", _]} ->
|
||||
@ -165,7 +165,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS},
|
||||
{"node", SNode}],
|
||||
[feature_to_xml({?NS_IQDATA})]}]};
|
||||
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]};
|
||||
{allow, ["running nodes", ENode, "backup"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes", ENode, "backup", _]} ->
|
||||
@ -173,7 +173,7 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS},
|
||||
{"node", SNode}],
|
||||
[feature_to_xml({?NS_IQDATA})]}]};
|
||||
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]};
|
||||
{allow, ["running nodes", ENode, "import"]} ->
|
||||
?EMPTY_INFO_RESULT;
|
||||
{allow, ["running nodes", ENode, "import", _]} ->
|
||||
@ -181,13 +181,13 @@ process_local_iq_info(From, _To, #iq{type = Type, xmlns = XMLNS,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS},
|
||||
{"node", SNode}],
|
||||
[feature_to_xml({?NS_IQDATA})]}]};
|
||||
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]};
|
||||
{allow, ["config", _]} ->
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query",
|
||||
[{"xmlns", XMLNS},
|
||||
{"node", SNode}],
|
||||
[feature_to_xml({?NS_IQDATA})]}]};
|
||||
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]};
|
||||
_ ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
|
||||
end
|
||||
@ -489,7 +489,7 @@ process_sm_iq_info(From, To, #iq{type = Type, xmlns = XMLNS,
|
||||
"" ->
|
||||
IQ#iq{type = result,
|
||||
sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}],
|
||||
[feature_to_xml({?NS_IQDATA})]}]};
|
||||
[feature_to_xml({?NS_EJABBERD_CONFIG})]}]};
|
||||
_ ->
|
||||
IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
|
||||
end
|
||||
|
@ -358,16 +358,16 @@ set_form(From, [], Lang, XData) ->
|
||||
{atomic, _} ->
|
||||
{result, []};
|
||||
_ ->
|
||||
{error, "406", "Not Acceptable"}
|
||||
{error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
_ ->
|
||||
{error, "406", "Not Acceptable"}
|
||||
{error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
_ ->
|
||||
{error, "406", "Not Acceptable"}
|
||||
{error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
_ ->
|
||||
{error, "406", "Not Acceptable"}
|
||||
{error, ?ERR_NOT_ACCEPTABLE}
|
||||
end;
|
||||
|
||||
|
||||
|
@ -63,7 +63,7 @@
|
||||
config = #config{},
|
||||
users = ?DICT:new(),
|
||||
affiliations = ?DICT:new(),
|
||||
history = lqueue_new(10),
|
||||
history = lqueue_new(20),
|
||||
subject = "",
|
||||
subject_author = ""}).
|
||||
|
||||
@ -831,7 +831,8 @@ add_new_user(From, Nick, {xmlelement, _, Attrs, Els} = Packet, StateData) ->
|
||||
add_online_user(From, Nick, Role, StateData)),
|
||||
send_new_presence(From, NewState),
|
||||
send_existing_presences(From, NewState),
|
||||
case send_history(From, NewState) of
|
||||
Shift = count_stanza_shift(Nick, Els, NewState),
|
||||
case send_history(From, Shift, NewState) of
|
||||
true ->
|
||||
ok;
|
||||
_ ->
|
||||
@ -879,7 +880,259 @@ extract_password([{xmlelement, Name, Attrs, SubEls} = El | Els]) ->
|
||||
extract_password([_ | Els]) ->
|
||||
extract_password(Els).
|
||||
|
||||
count_stanza_shift(Nick, Els, StateData) ->
|
||||
HL = lqueue_to_list(StateData#state.history),
|
||||
Since = extract_history(Els, "since"),
|
||||
Shift0 = case Since of
|
||||
false ->
|
||||
0;
|
||||
_ ->
|
||||
Sin = calendar:datetime_to_gregorian_seconds(Since),
|
||||
count_seconds_shift(Sin, HL)
|
||||
end,
|
||||
Seconds = extract_history(Els, "seconds"),
|
||||
Shift1 = case Seconds of
|
||||
false ->
|
||||
0;
|
||||
_ ->
|
||||
Sec = calendar:datetime_to_gregorian_seconds(
|
||||
calendar:now_to_universal_time(now())) - Seconds,
|
||||
count_seconds_shift(Sec, HL)
|
||||
end,
|
||||
MaxStanzas = extract_history(Els, "maxstanzas"),
|
||||
Shift2 = case MaxStanzas of
|
||||
false ->
|
||||
0;
|
||||
_ ->
|
||||
count_maxstanzas_shift(MaxStanzas, HL)
|
||||
end,
|
||||
MaxChars = extract_history(Els, "maxchars"),
|
||||
Shift3 = case MaxChars of
|
||||
false ->
|
||||
0;
|
||||
_ ->
|
||||
count_maxchars_shift(Nick, MaxChars, HL)
|
||||
end,
|
||||
lists:max([Shift0, Shift1, Shift2, Shift3]).
|
||||
|
||||
count_seconds_shift(Seconds, HistoryList) ->
|
||||
lists:sum(
|
||||
lists:map(
|
||||
fun({_Nick, _Packet, _HaveSubject, TimeStamp, _Size}) ->
|
||||
T = calendar:datetime_to_gregorian_seconds(TimeStamp),
|
||||
if
|
||||
T < Seconds ->
|
||||
1;
|
||||
true ->
|
||||
0
|
||||
end
|
||||
end, HistoryList)).
|
||||
|
||||
count_maxstanzas_shift(MaxStanzas, HistoryList) ->
|
||||
S = length(HistoryList) - MaxStanzas,
|
||||
if
|
||||
S =< 0 ->
|
||||
0;
|
||||
true ->
|
||||
S
|
||||
end.
|
||||
|
||||
count_maxchars_shift(Nick, MaxSize, HistoryList) ->
|
||||
NLen = string:len(Nick) + 1,
|
||||
Sizes = lists:map(
|
||||
fun({_Nick, _Packet, _HaveSubject, _TimeStamp, Size}) ->
|
||||
Size + NLen
|
||||
end, HistoryList),
|
||||
calc_shift(MaxSize, Sizes).
|
||||
|
||||
calc_shift(MaxSize, Sizes) ->
|
||||
Total = lists:sum(Sizes),
|
||||
calc_shift(MaxSize, Total, 0, Sizes).
|
||||
|
||||
calc_shift(_MaxSize, _Size, Shift, []) ->
|
||||
Shift;
|
||||
calc_shift(MaxSize, Size, Shift, [S | TSizes]) ->
|
||||
if
|
||||
MaxSize >= Size ->
|
||||
Shift;
|
||||
true ->
|
||||
calc_shift(MaxSize, Size - S, Shift + 1, TSizes)
|
||||
end.
|
||||
|
||||
extract_history([], Type) ->
|
||||
false;
|
||||
extract_history([{xmlelement, Name, Attrs, SubEls} = El | Els], Type) ->
|
||||
case xml:get_attr_s("xmlns", Attrs) of
|
||||
?NS_MUC ->
|
||||
AttrVal = xml:get_path_s(El,
|
||||
[{elem, "history"}, {attr, Type}]),
|
||||
case Type of
|
||||
"since" ->
|
||||
parse_datetime(AttrVal);
|
||||
_ ->
|
||||
case catch list_to_integer(AttrVal) of
|
||||
{'EXIT', _} ->
|
||||
false;
|
||||
IntVal ->
|
||||
if
|
||||
IntVal >= 0 ->
|
||||
IntVal;
|
||||
true ->
|
||||
false
|
||||
end
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
extract_history(Els, Type)
|
||||
end;
|
||||
extract_history([_ | Els], Type) ->
|
||||
extract_history(Els, Type).
|
||||
|
||||
% JEP-0082
|
||||
% yyyy-mm-ddThh:mm:ss[.sss]{Z|{+|-}hh:mm} -> {{yyyy, mm, dd}, {hh, mm, ss}} (UTC)
|
||||
parse_datetime(TimeStr) ->
|
||||
DateTime = string:tokens(TimeStr, "T"),
|
||||
case DateTime of
|
||||
[Date, Time] ->
|
||||
case parse_date(Date) of
|
||||
false ->
|
||||
false;
|
||||
D ->
|
||||
case parse_time(Time) of
|
||||
false ->
|
||||
false;
|
||||
{T, TZH, TZM} ->
|
||||
S = calendar:datetime_to_gregorian_seconds(
|
||||
{D, T}),
|
||||
calendar:gregorian_seconds_to_datetime(
|
||||
S - TZH * 60 * 60 - TZM * 60 * 30)
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
% yyyy-mm-dd
|
||||
parse_date(Date) ->
|
||||
YearMonthDay = string:tokens(Date, "-"),
|
||||
case length(YearMonthDay) of
|
||||
3 ->
|
||||
[Y, M, D] = lists:map(
|
||||
fun(L)->
|
||||
case catch list_to_integer(L) of
|
||||
{'EXIT', _} ->
|
||||
false;
|
||||
Int ->
|
||||
Int
|
||||
end
|
||||
end, YearMonthDay),
|
||||
case catch calendar:valid_date(Y, M, D) of
|
||||
true ->
|
||||
{Y, M, D};
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
% hh:mm:ss[.sss]TZD
|
||||
parse_time(Time) ->
|
||||
case string:str(Time, "Z") of
|
||||
0 ->
|
||||
parse_time_with_timezone(Time);
|
||||
_ ->
|
||||
[T | _] = string:tokens(Time, "Z"),
|
||||
case parse_time1(T) of
|
||||
false ->
|
||||
false;
|
||||
TT ->
|
||||
{TT, 0, 0}
|
||||
end
|
||||
end.
|
||||
|
||||
parse_time_with_timezone(Time) ->
|
||||
case string:str(Time, "+") of
|
||||
0 ->
|
||||
case string:str(Time, "-") of
|
||||
0 ->
|
||||
false;
|
||||
_ ->
|
||||
parse_time_with_timezone(Time, "-")
|
||||
end;
|
||||
_ ->
|
||||
parse_time_with_timezone(Time, "+")
|
||||
end.
|
||||
|
||||
parse_time_with_timezone(Time, Delim) ->
|
||||
TTZ = string:tokens(Time, Delim),
|
||||
case TTZ of
|
||||
[T, TZ] ->
|
||||
case parse_timezone(TZ) of
|
||||
false ->
|
||||
false;
|
||||
{TZH, TZM} ->
|
||||
case parse_time1(T) of
|
||||
false ->
|
||||
false;
|
||||
TT ->
|
||||
case Delim of
|
||||
"-" ->
|
||||
{TT, -TZH, -TZM};
|
||||
"+" ->
|
||||
{TT, TZH, TZM};
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
parse_timezone(TZ) ->
|
||||
case string:tokens(TZ, ":") of
|
||||
[H, M] ->
|
||||
case check_list([{H, 12}, {M, 60}]) of
|
||||
{[H, M], true} ->
|
||||
{H, M};
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
parse_time1(Time) ->
|
||||
case string:tokens(Time, ".") of
|
||||
[HMS | _] ->
|
||||
case string:tokens(HMS, ":") of
|
||||
[H, M, S] ->
|
||||
case check_list([{H, 24}, {M, 60}, {S, 60}]) of
|
||||
{[H1, M1, S1], true} ->
|
||||
{H1, M1, S1};
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
check_list(List) ->
|
||||
lists:mapfoldl(
|
||||
fun({L, N}, B)->
|
||||
case catch list_to_integer(L) of
|
||||
{'EXIT', _} ->
|
||||
{false, false};
|
||||
Int when (Int >= 0) and (Int =< N) ->
|
||||
{Int, B};
|
||||
_ ->
|
||||
{false, false}
|
||||
end
|
||||
end, true, List).
|
||||
|
||||
send_update_presence(JID, StateData) ->
|
||||
LJID = jlib:jid_tolower(JID),
|
||||
@ -1087,22 +1340,28 @@ add_message_to_history(FromNick, Packet, StateData) ->
|
||||
_ ->
|
||||
true
|
||||
end,
|
||||
TimeStamp = calendar:now_to_universal_time(now()),
|
||||
TSPacket = append_subtags(Packet,
|
||||
[jlib:timestamp_to_xml(
|
||||
calendar:now_to_universal_time(
|
||||
now()))]),
|
||||
Q1 = lqueue_in({FromNick, TSPacket, HaveSubject}, StateData#state.history),
|
||||
[jlib:timestamp_to_xml(TimeStamp)]),
|
||||
{xmlelement, Name, Attrs, Els} = TSPacket,
|
||||
SPacket = jlib:replace_from_to(
|
||||
jlib:jid_replace_resource(StateData#state.jid, FromNick),
|
||||
StateData#state.jid,
|
||||
TSPacket),
|
||||
Size = string:len(xml:element_to_string(SPacket)),
|
||||
Q1 = lqueue_in({FromNick, TSPacket, HaveSubject, TimeStamp, Size},
|
||||
StateData#state.history),
|
||||
StateData#state{history = Q1}.
|
||||
|
||||
send_history(JID, StateData) ->
|
||||
send_history(JID, Shift, StateData) ->
|
||||
lists:foldl(
|
||||
fun({Nick, Packet, HaveSubject}, B) ->
|
||||
fun({Nick, Packet, HaveSubject, _TimeStamp, _Size}, B) ->
|
||||
ejabberd_router:route(
|
||||
jlib:jid_replace_resource(StateData#state.jid, Nick),
|
||||
JID,
|
||||
Packet),
|
||||
B or HaveSubject
|
||||
end, false, lqueue_to_list(StateData#state.history)).
|
||||
end, false, lists:nthtail(Shift, lqueue_to_list(StateData#state.history))).
|
||||
|
||||
|
||||
send_subject(JID, StateData) ->
|
||||
|
@ -89,7 +89,7 @@ get_local_stats(["running nodes", _], []) ->
|
||||
get_local_stats(["running nodes", ENode], Names) ->
|
||||
case search_running_node(ENode) of
|
||||
false ->
|
||||
{error, "404", "Not Found"};
|
||||
{error, ?ERR_ITEM_NOT_FOUND};
|
||||
Node ->
|
||||
{result,
|
||||
lists:map(fun(Name) -> get_node_stat(Node, Name) end, Names)}
|
||||
|
Loading…
Reference in New Issue
Block a user