]> granicus.if.org Git - ejabberd/commitdiff
* src/mod_muc/mod_muc_room.erl: Send password in room invitation
authorAlexey Shchepin <alexey@process-one.net>
Fri, 17 Sep 2004 19:52:59 +0000 (19:52 +0000)
committerAlexey Shchepin <alexey@process-one.net>
Fri, 17 Sep 2004 19:52:59 +0000 (19:52 +0000)
(thanks to Sergei Golovan)

* src/mod_disco.erl: Added registration of sm features and nodes
(thanks to Sergei Golovan)
* src/mod_vcard.erl: Register vcard-temp feature (thanks to Sergei
Golovan)

* src/jlib.erl: Added functions now_to_utc_string/1,
now_to_local_string/1, and datetime_string_to_timestamp/1 (thanks
to Sergei Golovan)
* src/mod_muc/mod_muc_room.erl: Use time parsing functions from
jlib (thanks to Sergei Golovan)

* ejabberd/src/mod_pubsub/mod_pubsub.erl: Bugfix (thanks to
Mickael Remond)

* src/mod_pubsub/mod_pubsub.erl: Bugfix

SVN Revision: 265

ChangeLog
src/ejabberd_c2s.erl
src/jlib.erl
src/mod_disco.erl
src/mod_muc/mod_muc_room.erl
src/mod_pubsub/mod_pubsub.erl
src/mod_vcard.erl

index 4904367479de0e0c8ea3388f453a97aeae79a2b0..d2f599d0bc27f971f8aa64b6fde8f77c6dc7cffb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2004-09-17  Alexey Shchepin  <alexey@sevcom.net>
+
+       * src/mod_muc/mod_muc_room.erl: Send password in room invitation
+       (thanks to Sergei Golovan)
+
+       * src/mod_disco.erl: Added registration of sm features and nodes
+       (thanks to Sergei Golovan)
+       * src/mod_vcard.erl: Register vcard-temp feature (thanks to Sergei
+       Golovan)
+
+       * src/jlib.erl: Added functions now_to_utc_string/1,
+       now_to_local_string/1, and datetime_string_to_timestamp/1 (thanks
+       to Sergei Golovan)
+       * src/mod_muc/mod_muc_room.erl: Use time parsing functions from
+       jlib (thanks to Sergei Golovan)
+
+2004-09-16  Alexey Shchepin  <alexey@sevcom.net>
+
+       * ejabberd/src/mod_pubsub/mod_pubsub.erl: Bugfix (thanks to
+       Mickael Remond)
+
+2004-09-15  Alexey Shchepin  <alexey@sevcom.net>
+
+       * src/mod_pubsub/mod_pubsub.erl: Bugfix
+
 2004-09-10  Alexey Shchepin  <alexey@sevcom.net>
 
        * tools/ejabberdctl: Added call to "exec" (thanks to Sergei
index d8021606faa24e4614e54690ab54af90c02a3694..7452eb9c2aac50c95b52aa2e0701d5e0bc508045 100644 (file)
@@ -1354,7 +1354,7 @@ update_priority(El, StateData) ->
     ejabberd_sm:set_presence(StateData#state.user,
                             StateData#state.resource,
                             Pri).
-                 
+
 
 
 process_privacy_iq(From, To,
index 07ad933320182aba7514cbfce3af8b9f270c8c7d..ffd4e51d9219221086611e234c887eafca979afd 100644 (file)
@@ -37,6 +37,9 @@
         parse_xdata_submit/1,
         timestamp_to_iso/1,
         timestamp_to_xml/1,
+        now_to_utc_string/1,
+        now_to_local_string/1,
+        datetime_string_to_timestamp/1,
         decode_base64/1,
         encode_base64/1]).
 
@@ -438,6 +441,123 @@ timestamp_to_xml({{Year, Month, Day}, {Hour, Minute, Second}}) ->
                                [Year, Month, Day, Hour, Minute, Second]))}],
      []}.
 
+now_to_utc_string({MegaSecs, Secs, MicroSecs}) ->
+    {{Year, Month, Day}, {Hour, Minute, Second}} =
+       calendar:now_to_universal_time({MegaSecs, Secs, MicroSecs}),
+    lists:flatten(
+      io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w.~6..0wZ",
+                   [Year, Month, Day, Hour, Minute, Second, MicroSecs])).
+
+now_to_local_string({MegaSecs, Secs, MicroSecs}) ->
+    LocalTime = calendar:now_to_local_time({MegaSecs, Secs, MicroSecs}),
+    UTCTime = calendar:now_to_universal_time({MegaSecs, Secs, MicroSecs}),
+    Seconds = calendar:datetime_to_gregorian_seconds(LocalTime) -
+            calendar:datetime_to_gregorian_seconds(UTCTime),
+    {{H, M, _}, Sign} = if
+                           Seconds < 0 ->
+                               {calendar:seconds_to_time(-Seconds), "-"};
+                           true ->
+                               {calendar:seconds_to_time(Seconds), "+"}
+    end,
+    {{Year, Month, Day}, {Hour, Minute, Second}} = LocalTime,
+    lists:flatten(
+      io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w.~6..0w~s~2..0w:~2..0w",
+                   [Year, Month, Day, Hour, Minute, Second, MicroSecs, Sign, H, M])).
+
+
+% yyyy-mm-ddThh:mm:ss[.sss]{Z|{+|-}hh:mm} -> {MegaSecs, Secs, MicroSecs}
+datetime_string_to_timestamp(TimeStr) ->
+    case catch parse_datetime(TimeStr) of
+       {'EXIT', _Err} ->
+           undefined;
+       TimeStamp ->
+           TimeStamp
+    end.
+
+parse_datetime(TimeStr) ->
+    [Date, Time] = string:tokens(TimeStr, "T"),
+    D = parse_date(Date),
+    {T, MS, TZH, TZM} = parse_time(Time),
+    S = calendar:datetime_to_gregorian_seconds({D, T}),
+    S1 = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
+    Seconds = (S - S1) - TZH * 60 * 60 - TZM * 60,
+    {Seconds div 1000000, Seconds rem 1000000, MS}.
+
+% yyyy-mm-dd
+parse_date(Date) ->
+    [Y, M, D] = string:tokens(Date, "-"),
+    Date1 = {list_to_integer(Y), list_to_integer(M), list_to_integer(D)},
+    case calendar:valid_date(Date1) of
+       true ->
+           Date1;
+       _ ->
+           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"),
+           {TT, MS} = parse_time1(T),
+           {TT, MS, 0, 0}
+    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) ->
+    [T, TZ] = string:tokens(Time, Delim),
+    {TZH, TZM} = parse_timezone(TZ),
+    {TT, MS} = parse_time1(T),
+    case Delim of
+       "-" ->
+           {TT, MS, -TZH, -TZM};
+       "+" ->
+           {TT, MS, TZH, TZM}
+    end.
+
+parse_timezone(TZ) ->
+    [H, M] = string:tokens(TZ, ":"),
+    {[H1, M1], true} = check_list([{H, 12}, {M, 60}]),
+    {H1, M1}.
+
+parse_time1(Time) ->
+    [HMS | T] =  string:tokens(Time, "."),
+    MS = case T of
+            [] ->
+                0;
+            [Val] ->
+                list_to_integer(string:left(Val, 6, $0))
+        end,
+    [H, M, S] = string:tokens(HMS, ":"),
+    {[H1, M1, S1], true} = check_list([{H, 24}, {M, 60}, {S, 60}]),
+    {{H1, M1, S1}, MS}.
+
+check_list(List) ->
+    lists:mapfoldl(
+      fun({L, N}, B)->
+         V = list_to_integer(L),
+         if
+             (V >= 0) and (V =< N) ->
+                 {V, B};
+             true ->
+                 {false, false}
+         end
+      end, true, List).
+
 
 %
 % Base64 stuff (based on httpd_util.erl)
index af992df0bdb87123de7e9253d74948a8d3b00f0a..3a7578ddf0dfc229ad6629e1f35ed1ccb2bb2eb2 100644 (file)
         register_feature/1,
         unregister_feature/1,
         register_extra_domain/1,
-        unregister_extra_domain/1]).
+        unregister_extra_domain/1,
+        register_sm_feature/1,
+        unregister_sm_feature/1,
+        register_sm_node/4,
+        unregister_sm_node/1]).
 
 -include("ejabberd.hrl").
 -include("jlib.hrl").
@@ -53,6 +57,8 @@ start(Opts) ->
     catch ets:new(disco_extra_domains, [named_table, ordered_set, public]),
     ExtraDomains = gen_mod:get_opt(extra_domains, Opts, []),
     lists:foreach(fun register_extra_domain/1, ExtraDomains),
+    catch ets:new(disco_sm_features, [named_table, ordered_set, public]),
+    catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]),
     ok.
 
 stop() ->
@@ -463,43 +469,108 @@ get_stopped_nodes(Lang) ->
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-process_sm_iq_items(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
-    #jid{user = User} = To,
-    case {acl:match_rule(configure, From), Type} of
-       {deny, _} ->
+register_sm_feature(Feature) ->
+    catch ets:new(disco_sm_features, [named_table, ordered_set, public]),
+    ets:insert(disco_sm_features, {Feature}).
+
+unregister_sm_feature(Feature) ->
+    catch ets:new(disco_sm_features, [named_table, ordered_set, public]),
+    ets:delete(disco_sm_features, Feature).
+
+register_sm_node(Node, Name, Module, Function) ->
+    catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]),
+    ets:insert(disco_sm_nodes, {Node, Name, Module, Function}).
+
+unregister_sm_node(Node) ->
+    catch ets:new(disco_sm_nodes, [named_table, ordered_set, public]),
+    ets:delete(disco_sm_nodes, Node).
+
+process_sm_iq_items(From, To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
+    #jid{user = User, luser = LTo} = To,
+    #jid{luser = LFrom, lserver = LServer} = From,
+    Self = (LTo == LFrom) andalso (LServer == ?MYNAME),
+    Node = xml:get_tag_attr_s("node", SubEl),
+    case {acl:match_rule(configure, From), Type, Self, Node} of
+       {_, set, _, _} ->
            IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
-       {allow, set} ->
-           IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
-       {allow, get} ->
-           case xml:get_tag_attr_s("node", SubEl) of
-               "" ->
-                   IQ#iq{type = result,
-                         sub_el = [{xmlelement, "query",
-                                    [{"xmlns", ?NS_DISCO_ITEMS}],
-                                    get_user_resources(User)
-                                   }]};
-               _ ->
-                   IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
-           end
+       {_, get, true, []}  ->
+           Nodes = lists:map(fun({Nod, Name, _, _}) ->
+                                       node_to_xml(User,
+                                       Nod,
+                                       translate:translate(Lang, Name))
+                             end, ets:tab2list(disco_sm_nodes)),
+           IQ#iq{type = result,
+                 sub_el = [{xmlelement, "query",
+                            [{"xmlns", ?NS_DISCO_ITEMS}],
+                            get_user_resources(User) ++ Nodes}]};
+       {allow, get, _, []} ->
+           Nodes = lists:map(fun({Nod, Name, _, _}) ->
+                                       node_to_xml(User,
+                                       Nod,
+                                       translate:translate(Lang, Name))
+                             end, ets:tab2list(disco_sm_nodes)),
+           IQ#iq{type = result,
+                 sub_el = [{xmlelement, "query",
+                            [{"xmlns", ?NS_DISCO_ITEMS}],
+                            get_user_resources(User) ++ Nodes}]};
+       {A, get, S, _} when (A == allow) or (S == true) ->
+           case ets:lookup(disco_sm_nodes, Node) of
+               [] ->
+                   IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]};
+               [{Node, _Name, Module, Function}] ->
+                   case Module:Function(From, To, IQ) of
+                       {error, Err} ->
+                           IQ#iq{type = error, sub_el = [SubEl, Err]};
+                       {result, Res} ->
+                           IQ#iq{type = result,
+                                 sub_el = [{xmlelement, "query",
+                                            [{"xmlns", ?NS_DISCO_ITEMS},
+                                             {"node", Node}],
+                                            Res}]}
+                   end
+           end;
+       {_, get, _, _} ->
+           IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]};
+       _ ->
+           IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
     end.
 
 
 process_sm_iq_info(From, To, #iq{type = Type, xmlns = XMLNS,
                                 sub_el = SubEl} = IQ) ->
-    case {acl:match_rule(configure, From), Type} of
-       {deny, _} ->
+    #jid{luser = LTo} = To,
+    #jid{luser = LFrom, lserver = LServer} = From,
+    Self = (LTo == LFrom) andalso (LServer == ?MYNAME),
+    Node = xml:get_tag_attr_s("node", SubEl),
+    case {acl:match_rule(configure, From), Type, Self, Node} of
+       {_, set, _, _} ->
            IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
-       {allow, set} ->
-           IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
-       {allow, get} ->
-           case xml:get_tag_attr_s("node", SubEl) of
-               "" ->
-                   IQ#iq{type = result,
-                         sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}],
-                                    [feature_to_xml({?NS_EJABBERD_CONFIG})]}]};
+       {allow, get, _, []} ->
+           Features = lists:map(fun feature_to_xml/1,
+                                ets:tab2list(disco_sm_features)),
+           IQ#iq{type = result,
+                 sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}],
+                            [feature_to_xml({?NS_EJABBERD_CONFIG})] ++
+                            Features}]};
+       {_, get, _, []} ->
+           Features = lists:map(fun feature_to_xml/1,
+                                ets:tab2list(disco_sm_features)),
+           IQ#iq{type = result,
+                 sub_el = [{xmlelement, "query", [{"xmlns", XMLNS}],
+                           Features}]};
+       {A, get, S, _} when (A == allow) or (S == true) ->
+           case ets:lookup(disco_sm_nodes, Node) of
+               [] ->
+                   IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]};
                _ ->
-                   IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}
-           end
+                   IQ#iq{type = result, sub_el = [{xmlelement, "query",
+                                                  [{"xmlns", XMLNS},
+                                                   {"node", Node}], []}]}
+           end;
+       {_, get, _, _} ->
+           IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]};
+       _ ->
+           IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]}
     end.
 
 
@@ -512,3 +583,8 @@ get_user_resources(User) ->
                        {"name", User}], []}
              end, lists:sort(Rs)).
 
+node_to_xml(User, Node, Name) ->
+    {xmlelement, "item", [{"jid", User ++ "@" ++ ?MYNAME},
+                         {"node", Node},
+                         {"name", Name}], []}.
+
index ba6187d6b8123e0d970655c4cb193bc40cb9b05b..17aaeacaabb8fead95b8f63eea9818998f79f1d8 100644 (file)
@@ -1079,23 +1079,18 @@ extract_history([{xmlelement, _Name, Attrs, _SubEls} = El | Els], Type) ->
                       [{elem, "history"}, {attr, Type}]),
            case Type of
                "since" ->
-                   case catch parse_datetime(AttrVal) of
-                       {'EXIT', _Err} ->
+                   case jlib:datetime_string_to_timestamp(AttrVal) of
+                       undefined ->
                            false;
-                       Res ->
-                           Res
+                       TS ->
+                           calendar:now_to_universal_time(TS)
                    end;
                _ ->
                    case catch list_to_integer(AttrVal) of
-                       {'EXIT', _} ->
-                           false;
-                       IntVal ->
-                           if
-                               IntVal >= 0 ->
-                                   IntVal;
-                               true ->
-                                   false
-                           end
+                       IntVal when is_integer(IntVal) and IntVal >= 0 ->
+                           IntVal;
+                       _ ->
+                           false
                    end
            end;
        _ ->
@@ -1104,80 +1099,6 @@ extract_history([{xmlelement, _Name, Attrs, _SubEls} = El | Els], Type) ->
 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) ->
-    [Date, Time] = string:tokens(TimeStr, "T"),
-    D = parse_date(Date),
-    {T, TZH, TZM} = parse_time(Time),
-    S = calendar:datetime_to_gregorian_seconds({D, T}),
-    calendar:gregorian_seconds_to_datetime(S - TZH * 60 * 60 - TZM * 60).
-
-% yyyy-mm-dd
-parse_date(Date) ->
-    YearMonthDay = string:tokens(Date, "-"),
-    [Y, M, D] = lists:map(
-                 fun(L)->
-                     list_to_integer(L)
-                 end, YearMonthDay),
-    {Y, M, D}.
-
-% 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"),
-           {parse_time1(T), 0, 0}
-    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) ->
-    [T, TZ] = string:tokens(Time, Delim),
-    {TZH, TZM} = parse_timezone(TZ),
-    TT = parse_time1(T),
-    case Delim of
-       "-" ->
-           {TT, -TZH, -TZM};
-       "+" ->
-           {TT, TZH, TZM}
-    end.
-
-parse_timezone(TZ) ->
-    [H, M] = string:tokens(TZ, ":"),
-    {[H1, M1], true} = check_list([{H, 12}, {M, 60}]),
-    {H1, M1}.
-
-parse_time1(Time) ->
-    [HMS | _] =  string:tokens(Time, "."),
-    [H, M, S] = string:tokens(HMS, ":"),
-    {[H1, M1, S1], true} = check_list([{H, 24}, {M, 60}, {S, 60}]),
-    {H1, M1, S1}.
-
-check_list(List) ->
-    lists:mapfoldl(
-      fun({L, N}, B)->
-         V = list_to_integer(L),
-         if
-             (V >= 0) and (V =< N) ->
-                 {V, B};
-             true ->
-                 {false, false}
-         end
-      end, true, List).
 
 send_update_presence(JID, StateData) ->
     LJID = jlib:jid_tolower(JID),
@@ -2316,7 +2237,14 @@ check_invitation(From, Els, StateData) ->
                                                    jlib:jid_to_string(From)}],
                                                  [{xmlelement, "reason", [],
                                                    [{xmlcdata, Reason}]}]}],
-                                           PasswdEl = [],
+                                           PasswdEl = 
+                                               case (StateData#state.config)#config.password_protected of
+                                                   true ->
+                                                       [{xmlelement, "password", [],
+                                                       [{xmlcdata, (StateData#state.config)#config.password}]}];
+                                                   _ ->
+                                                       []
+                                               end,
                                            Msg =
                                                {xmlelement, "message",
                                                 [{"type", "normal"}],
index 3acd0a76d93d32cbce5c040607c7d82b252a4d9c..3a9a93c6a827f5867b2137f801c1a5e323a03c06 100644 (file)
@@ -452,6 +452,8 @@ iq_pubsub(Host, From, Type, SubEl) ->
         [{xmlelement, "value", [], [{xmlcdata, Val}]}]}).
 
 
+%% Create new pubsub nodes
+%% This function is used during init to create the first bootstrap nodes
 create_new_node(Host, Node, Owner) ->
     case Node of
        [] ->
@@ -867,7 +869,7 @@ set_entities(OJID, Node, EntitiesEls) ->
                                      (Subscription == false) ->
                                          error;
                                      true ->
-                                         [{JID,
+                                         [{jlib:jid_tolower(JID),
                                            #entity{
                                              affiliation = Affiliation,
                                              subscription = Subscription}} |
@@ -984,7 +986,7 @@ subscription_to_string(Subscription) ->
 
 check_create_permission(Host, Node, Owner) ->
     if
-       #jid{lserver = Host} == Owner ->
+       Owner#jid.lserver == Host ->
            true;
        true ->
            #jid{luser = User, lserver = Server} = Owner,
index 854df2c0aa621293a11daa90e62833c78c03c8d4..49c0728dc39ab86e8eebbcd555d7710d6a569436 100644 (file)
@@ -64,6 +64,7 @@ start(Opts) ->
                                  ?MODULE, process_local_iq, IQDisc),
     gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_VCARD,
                                  ?MODULE, process_sm_iq, IQDisc),
+    catch mod_disco:register_sm_feature(?NS_VCARD),
     Host = gen_mod:get_opt(host, Opts, "vjud." ++ ?MYNAME),
     Search = gen_mod:get_opt(search, Opts, true),
     register(ejabberd_mod_vcard, spawn(?MODULE, init, [Host, Search])).
@@ -98,6 +99,7 @@ loop(Host) ->
 stop() ->
     gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_VCARD),
     gen_iq_handler:remove_iq_handler(ejabberd_sm, ?NS_VCARD),
+    catch mod_disco:unregister_sm_feature(?NS_VCARD),
     ejabberd_mod_vcard ! stop,
     ok.